Railway Operation Simulator  v2.7.0
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 // TrackUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 #include <Classes.hpp>
27 #include <Controls.hpp>
28 #include <StdCtrls.hpp>
29 #include <Forms.hpp>
30 #include <Buttons.hpp>
31 #include <ExtCtrls.hpp>
32 #include <Menus.hpp>
33 #include <Dialogs.hpp>
34 #include <Graphics.hpp>
35 #include <ComCtrls.hpp>
36 #include <fstream>
37 #include <vector>
38 #include <algorithm> //for std::find
39 #include <vcl.h>
40 
41 #pragma hdrstop
42 
43 #include "TrackUnit.h"
44 #include "Utilities.h"
45 // #include "DisplayUnit.h" included in header file
46 #include "GraphicUnit.h"
47 #include "TextUnit.h"
48 #include "TrainUnit.h"
49 
50 #pragma package(smart_init)
51 // ---------------------------------------------------------------------------
52 
55 
56 // ---------------------------------------------------------------------------
57 
58 // FIXED TRACK :-
59 
60 // Constructor to build TrackPieces from array
61 
62 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
63  Graphics::TBitmap* SmallGraphicPtrVal): SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
64 {
65  for(int x = 0; x < 4; x++)
66  {
67  Link[x] = LkVal[x];
68  Config[x] = ConfigVal[x];
69  }
70 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
71  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
72  if(SpeedTagVal == 76)
74  else if(SpeedTagVal == 77)
76  else if(SpeedTagVal == 78)
78  else if(SpeedTagVal == 79)
80  else if(SpeedTagVal == 96)
82  else if(SpeedTagVal == 129)
84  else if(SpeedTagVal == 130)
86  else if(SpeedTagVal == 131)
88  else if(SpeedTagVal == 145)
90  else if(SpeedTagVal == 146)
92 }
93 
94 // ---------------------------------------------------------------------------
95 
96 TFixedTrackPiece::TFixedTrackPiece(): SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
97  FixedNamedLocationElement(false) // default values
98 {
99  for(int x = 0; x < 4; x++)
100  {
101  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
102  Config[x] = NotSet;
103  }
104 }
105 
106 // ---------------------------------------------------------------------------
107 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
108 {
109  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
110  AnsiString(VLocInput));
111  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
112  Utilities->CallLogPop(1331);
113 }
114 
115 // ---------------------------------------------------------------------------
116 
117 // VARIABLE TRACK :-
118 
119 // ---------------------------------------------------------------------------
120 
122 {
123  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
124  return true;
125  else
126  return false;
127 }
128 
129 // ---------------------------------------------------------------------------
130 
132 {
133  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
134  return true;
135  else
136  return false;
137 }
138 
139 // ---------------------------------------------------------------------------
140 
142  // 'Variable' in the sense that element might be striped or non-striped
143 {
144  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
145  Graphics::TBitmap *GraphicOutput = GraphicPtr;
146 
147  if(LocationName == "")
148  {
149  switch(SpeedTag)
150  {
151  case 76: // t platform
152  GraphicOutput = RailGraphics->gl76Striped;
153  break;
154 
155  case 77: // h platform
156  GraphicOutput = RailGraphics->bm77Striped;
157  break;
158 
159  case 78: // v platform
160  GraphicOutput = RailGraphics->bm78Striped;
161  break;
162 
163  case 79: // r platform
164  GraphicOutput = RailGraphics->gl79Striped;
165  break;
166 
167  case 96: // concourse
168  GraphicOutput = RailGraphics->ConcourseStriped;
169  break;
170 
171  case 129: // v footbridge
172  GraphicOutput = RailGraphics->gl129Striped;
173  break;
174 
175  case 130: // h footbridge
176  GraphicOutput = RailGraphics->gl130Striped;
177  break;
178 
179  case 131: // non-station named loc
180  GraphicOutput = RailGraphics->bmNameStriped;
181  break;
182 
183  case 145: // v underpass
184  GraphicOutput = RailGraphics->gl145Striped;
185  break;
186 
187  case 146: // h underpass
188  GraphicOutput = RailGraphics->gl146Striped;
189  break;
190 
191  default:
192  GraphicOutput = GraphicPtr;
193  break;
194  }
195  }
196  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
197  Utilities->CallLogPop(1332);
198 }
199 
200 // ---------------------------------------------------------------------------
201 
202 AnsiString TTrackElement::LogTrack(int Caller) const
203  // for debugging when passes as a call parameter
204 {
205  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
206  AnsiString(TrainIDOnBridgeTrackPos01) + "," + AnsiString(TrainIDOnBridgeTrackPos23) + ",EndTrkEl,";
207 
208  return LogString;
209 }
210 
211 // ---------------------------------------------------------------------------
212 
213 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
214 {
215  if(lower.second < higher.second)
216  {
217  return true;
218  }
219  else if(lower.second > higher.second)
220  {
221  return false;
222  }
223  else if(lower.second == higher.second)
224  {
225  if(lower.first < higher.first)
226  {
227  return true;
228  }
229  }
230  return false;
231 }
232 
233 // ---------------------------------------------------------------------------
234 // PrefDirElement Functions
235 // ---------------------------------------------------------------------------
236 
237 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
238  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
239  CheckCount(9), IsARoute(false), AutoSignals(false), PrefDirRoute(false)
240 {
241  if(!EntryExitNumber())
242  {
243  throw Exception("EXNumber failure in TPrefDirElement constructor");
244  }
247 }
248 
249 // ---------------------------------------------------------------------------
250 
251 AnsiString TPrefDirElement::LogPrefDir() const
252  // for debugging when passed as a call parameter
253 {
254  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
255  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)PrefDirRoute) +
256  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeTrackPos01) + "," +
257  AnsiString(TrainIDOnBridgeTrackPos23);
258 
259 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
260  return LogString;
261 }
262 
263 // ---------------------------------------------------------------------------
264 
265 bool TPrefDirElement::EntryExitNumber() // true for valid number
266 /*
267  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
268  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
269  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
270  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
271  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
272  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
273  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
274  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
275  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
276 */
277 
278 {
279  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
280  int EXArray[16][2] =
281  {{4, 6}, {2, 8}, // horizontal & vertical
282  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
283  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
284  {1, 9}, {3, 7}}; // forward & reverse diagonals
285 
286  int EXNum = -1;
287  int Entry, Exit;
288 
289  if(ELink > -1)
290  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
291  else if(Link[2] == -1)
292  Entry = Link[0];
293  else
294  {
295  Utilities->CallLogPop(122);
296  return false;
297  }
298  if(XLink > -1)
299  Exit = XLink;
300  else if(Link[2] == -1)
301  Exit = Link[1];
302  else
303  {
304  Utilities->CallLogPop(123);
305  return false;
306  }
307 
308  for(int x = 0; x < 16; x++)
309  {
310  if((Entry == EXArray[x][0]) && (Exit == EXArray[x][1]) || (Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))
311  {
312  EXNum = x;
313  }
314  }
315  if(EXNum == -1)
316  {
317  Utilities->CallLogPop(124);
318  return false;
319  }
320 
321  int BrNum = -1;
322 
323 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
324  the graphic for each of which is different because of the shape of the overbridge. The basic
325  entry/exit value is computed above, and this used to select only from elements with that entry/exit
326  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
327  int BrEXArray[24][2] = {
328  {4,6},{2,8},{1,9},{3,7},
329  {1,9},{3,7},{1,9},{3,7},
330  {2,8},{4,6},{2,8},{4,6}
331 */
332 
333  if(TrackType == Bridge)
334  {
335  if(EXNum == 1)
336  {
337  if(SpeedTag == 49)
338  BrNum = 1 + 16;
339  else if(SpeedTag == 54)
340  BrNum = 8 + 16;
341  else if(SpeedTag == 55)
342  BrNum = 10 + 16;
343  }
344  else if(EXNum == 0)
345  {
346  if(SpeedTag == 48)
347  BrNum = 0 + 16;
348  else if(SpeedTag == 58)
349  BrNum = 11 + 16;
350  else if(SpeedTag == 59)
351  BrNum = 9 + 16;
352  }
353  else if(EXNum == 14)
354  {
355  if(SpeedTag == 50)
356  BrNum = 2 + 16;
357  else if(SpeedTag == 52)
358  BrNum = 4 + 16;
359  else if(SpeedTag == 57)
360  BrNum = 6 + 16;
361  }
362  else if(EXNum == 15)
363  {
364  if(SpeedTag == 51)
365  BrNum = 3 + 16;
366  else if(SpeedTag == 53)
367  BrNum = 7 + 16;
368  else if(SpeedTag == 56)
369  BrNum = 5 + 16;
370  }
371  }
372  if(BrNum == -1)
373  EXNumber = EXNum;
374  else
375  EXNumber = BrNum;
376  Utilities->CallLogPop(125);
377  return true;
378 }
379 
380 // ---------------------------------------------------------------------------
381 
383 /*
384  This is the basic track graphic for use in plotting the original graphic during route flashing.
385  Enter with all set apart from EXGraphic & EntryDirectionGraphic
386 */
387 {
388  if(SpeedTag == 64)
389  return RailGraphics->LinkGraphicsPtr[16]; // intercept diagonal buffers
390 
391  if(SpeedTag == 65)
392  return RailGraphics->LinkGraphicsPtr[17];
393 
394  if(SpeedTag == 66)
395  return RailGraphics->LinkGraphicsPtr[18];
396 
397  if(SpeedTag == 67)
398  return RailGraphics->LinkGraphicsPtr[19];
399 
400  if(SpeedTag == 80)
401  return RailGraphics->LinkGraphicsPtr[20]; // intercept continuations
402 
403  if(SpeedTag == 81)
404  return RailGraphics->LinkGraphicsPtr[21];
405 
406  if(SpeedTag == 82)
407  return RailGraphics->LinkGraphicsPtr[22];
408 
409  if(SpeedTag == 83)
410  return RailGraphics->LinkGraphicsPtr[23];
411 
412  if(SpeedTag == 84)
413  return RailGraphics->LinkGraphicsPtr[24];
414 
415  if(SpeedTag == 85)
416  return RailGraphics->LinkGraphicsPtr[25];
417 
418  if(SpeedTag == 86)
419  return RailGraphics->LinkGraphicsPtr[26];
420 
421  if(SpeedTag == 87)
422  return RailGraphics->LinkGraphicsPtr[27];
423 
424  if(SpeedTag == 129)
425  return RailGraphics->LinkGraphicsPtr[28]; // intercept under footbridges
426 
427  if(SpeedTag == 130)
428  return RailGraphics->LinkGraphicsPtr[29];
429 
430  if(XLinkPos == -1) // not set, could be first element or last element = leading point
431  {
432 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
433 // Points & don't want to display these)
434  if(Link[2] != -1)
435  return 0; // i.e. complex element, don't display
436  else
437  {
438  if(!EntryExitNumber())
439  {
440  throw Exception("Error in EntryExitNumber 4");
441  }
442  else
443  {
445  }
446  }
447  }
448  if(EXNumber > 15) // underbridge
449  {
451  }
452  else
453  {
455  }
456 }
457 
458 // ---------------------------------------------------------------------------
459 
461 /*
462  As above but for PrefDir graphics.
463 */
464 {
465  if(SpeedTag == 64)
466  return RailGraphics->LinkPrefDirGraphicsPtr[16]; // intercept diagonal buffers
467 
468  if(SpeedTag == 65)
470 
471  if(SpeedTag == 66)
473 
474  if(SpeedTag == 67)
476 
477  if(SpeedTag == 80)
478  return RailGraphics->LinkPrefDirGraphicsPtr[20]; // intercept continuations
479 
480  if(SpeedTag == 81)
482 
483  if(SpeedTag == 82)
485 
486  if(SpeedTag == 83)
488 
489  if(SpeedTag == 84)
491 
492  if(SpeedTag == 85)
494 
495  if(SpeedTag == 86)
497 
498  if(SpeedTag == 87)
500 
501  if(SpeedTag == 129)
502  return RailGraphics->LinkPrefDirGraphicsPtr[28]; // intercept under footbridges
503 
504  if(SpeedTag == 130)
506 
507  if(XLinkPos == -1) // not set, could be first element or last element = leading point
508  {
509 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
510  if(Link[2] != -1)
511  return 0; // i.e. complex element, don't display
512  else
513  {
514  if(!EntryExitNumber())
515  {
516  throw Exception("Error in EntryExitNumber 5");
517  }
518  else
520  }
521  }
522  if(EXNumber > 15) // underbridge
523  {
525  }
526  else
528 }
529 
530 // ---------------------------------------------------------------------------
531 
532 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
533 /*
534  As above but for route graphics.
535 */
536 {
537  if(!AutoSigsFlag && !PrefDirRoute)
538  {
539  if(SpeedTag == 64)
540  return RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers
541 
542  if(SpeedTag == 65)
544 
545  if(SpeedTag == 66)
547 
548  if(SpeedTag == 67)
550 
551  if(SpeedTag == 80)
552  return RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations
553 
554  if(SpeedTag == 81)
556 
557  if(SpeedTag == 82)
559 
560  if(SpeedTag == 83)
562 
563  if(SpeedTag == 84)
565 
566  if(SpeedTag == 85)
568 
569  if(SpeedTag == 86)
571 
572  if(SpeedTag == 87)
574 
575  if(SpeedTag == 129)
576  return RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
577 
578  if(SpeedTag == 130)
580 
581  if(XLinkPos == -1) // not set, could be first element or last element = leading point
582  {
583  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
584  if(Link[2] != -1)
585  return 0; // i.e. complex element, don't display
586  else
587  {
588  if(!EntryExitNumber())
589  {
590  throw Exception("Error in EntryExitNumber 6");
591  }
592  else
594  }
595  }
596  if(EXNumber > 15) // underbridge
597  {
599  }
600  else
602  }
603 
604  else if(!AutoSigsFlag && PrefDirRoute)
605  {
606  if(SpeedTag == 64)
607  return RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers
608 
609  if(SpeedTag == 65)
611 
612  if(SpeedTag == 66)
614 
615  if(SpeedTag == 67)
617 
618  if(SpeedTag == 80)
619  return RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations
620 
621  if(SpeedTag == 81)
623 
624  if(SpeedTag == 82)
626 
627  if(SpeedTag == 83)
629 
630  if(SpeedTag == 84)
632 
633  if(SpeedTag == 85)
635 
636  if(SpeedTag == 86)
638 
639  if(SpeedTag == 87)
641 
642  if(SpeedTag == 129)
643  return RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
644 
645  if(SpeedTag == 130)
647 
648  if(XLinkPos == -1) // not set, could be first element or last element = leading point
649  {
650  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
651  if(Link[2] != -1)
652  return 0; // i.e. complex element, don't display
653  else
654  {
655  if(!EntryExitNumber())
656  {
657  throw Exception("Error in EntryExitNumber 10");
658  }
659  else
661  }
662  }
663  if(EXNumber > 15) // underbridge
664  {
666  }
667  else
669  }
670 
671  else
672  {
673  if(SpeedTag == 64)
674  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers
675 
676  if(SpeedTag == 65)
678 
679  if(SpeedTag == 66)
681 
682  if(SpeedTag == 67)
684 
685  if(SpeedTag == 80)
686  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations
687 
688  if(SpeedTag == 81)
690 
691  if(SpeedTag == 82)
693 
694  if(SpeedTag == 83)
696 
697  if(SpeedTag == 84)
699 
700  if(SpeedTag == 85)
702 
703  if(SpeedTag == 86)
705 
706  if(SpeedTag == 87)
708 
709  if(SpeedTag == 129)
710  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
711 
712  if(SpeedTag == 130)
714 
715  if(XLinkPos == -1) // not set, could be first element or last element = leading point
716  {
717  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
718  if(Link[2] != -1)
719  return 0; // i.e. complex element, don't display
720  else
721  {
722  if(!EntryExitNumber())
723  {
724  throw Exception("Error in EntryExitNumber 11");
725  }
726  else
728  }
729  }
730  if(EXNumber > 15) // underbridge
731  {
733  }
734  else
736  }
737 }
738 
739 // ---------------------------------------------------------------------------
740 
742 /*
743  As above but for route flashing graphics. (Disused - now combined with above)
744 */
745 {
746  if(SpeedTag == 64)
747  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers
748 
749  if(SpeedTag == 65)
751 
752  if(SpeedTag == 66)
754 
755  if(SpeedTag == 67)
757 
758  if(SpeedTag == 80)
759  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations
760 
761  if(SpeedTag == 81)
763 
764  if(SpeedTag == 82)
766 
767  if(SpeedTag == 83)
769 
770  if(SpeedTag == 84)
772 
773  if(SpeedTag == 85)
775 
776  if(SpeedTag == 86)
778 
779  if(SpeedTag == 87)
781 
782  if(SpeedTag == 129)
783  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
784 
785  if(SpeedTag == 130)
787 
788  if(XLinkPos == -1) // not set, could be first element or last element = leading point
789  {
790 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
791  if(Link[2] != -1)
792  return 0; // i.e. complex element, don't display
793  else
794  {
795  if(!EntryExitNumber())
796  {
797  throw Exception("Error in EntryExitNumber 7");
798  }
799  else
801  }
802  }
803  if(EXNumber > 15) // underbridge
804  {
806  }
807  else
809 }
810 
811 // ---------------------------------------------------------------------------
812 
814 /*
815  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
816 */
817 {
818  if((ELink > 0) && (ELink < 10) && (ELink != 5))
820  else
821  {
822  throw Exception("Error in EntryExitNumber 8");
823  }
824 }
825 
826 // ---------------------------------------------------------------------------
827 
828 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
829 /*
830  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
831 */
832 {
833  if((ELink > 0) && (ELink < 10) && (ELink != 5))
834  {
835  if(!AutoSigsFlag && !PrefDirRoute)
837  else if(!AutoSigsFlag && PrefDirRoute)
839  else
841  }
842  else
843  {
844  throw Exception("Error in EntryExitNumber 9");
845  }
846 }
847 
848 // ---------------------------------------------------------------------------
849 
851 /*
852  Set == operator when TrackVectorPosition, ELink & XLink all same
853 */
854 {
855  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
856  return true;
857  else
858  return false;
859 }
860 
861 // ---------------------------------------------------------------------------
862 
864 /*
865  Set != operator when any of TrackVectorPosition, ELink or XLink different
866 */
867 {
868  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
869  return false;
870  else
871  return true;
872 }
873 
874 // ---------------------------------------------------------------------------
875 // Track functions
876 // ---------------------------------------------------------------------------
877 
878 // ---------------------------------------------------------------------------
879 
880 TTrack::TActiveLevelCrossing::TActiveLevelCrossing()
881 {
882  TypeOfRoute = 0;
883  ReducedTimePenalty = false;
884  BarrierState = Up;
885  ChangeDuration = 0.0;
887  HLoc = 0;
888  VLoc = 0;
889  StartTime = TDateTime(0);
890 }
891 
892 // ---------------------------------------------------------------------------
893 
895 {
896 // CurrentSpeedButtonTag = 0; //not assigned yet
897 
898  HLocMin = 2000000000;
899  VLocMin = 2000000000;
900  HLocMax = -2000000000;
901  VLocMax = -2000000000;
902  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
903  CopyFlag = false; // only true for copying, so names aren't copied
904 
905  AnsiString NL = '\n';
906 
907  RouteFailMessage = "Unable to set a route:" + NL + NL + "it may be unreachable; " + NL + NL +
908  "reachable but with too many different directions leading away from the start point - set some points on the route required; " + NL + NL +
909  "blocked by a train, another route or a changing level crossing; " + NL + NL +
910  "or invalid - possibly due to a preferred direction mismatch, or a missed signal in a blue route or green route restricted to consecutive signals.";
911 
916 
917  int InternalLinkCheckArray[9][2] =
918  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
919 
920 /* array of valid link values for 'old' location and 'new' location, where
921  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
922 
923  for(int x = 0; x < 9; x++)
924  for(int y = 0; y < 2; y++)
925  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
926 
927 // Platform and default track element values
928  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
929 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
930  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
931  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
932  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
933  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 20 << 21 << 22 << 23 << 24 << 25 << 26 << 27 // disallow diagonals, points, crossovers, bridges, gaps,
934  << 60 << 61 << 62 << 63 << 68 << 69 << 70 << 71 << 80 << 81 << 82 << 83 << 125 << 126 << 127 << 128; // diag continuations, diag buffers, footcrossings (diagonals may be OK
935  // but as can't link diagonal locations would need solid blocks to allow linkage & that would look untidy except for single
936  // elements, & can always use straights so leave out.) Allow horiz & vert signals as from v2.6.0
937  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
938 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
939 
940  int HVArray[10][2] =
941  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
942 
943  for(int x = 0; x < 10; x++)
944  for(int y = 0; y < 2; y++)
945  LinkHVArray[x][y] = HVArray[x][y];
946  TrackFinished = false;
947 // DistancesSet = false;
948 
949  TSigElement TempSigTable[40] = // original four aspect
950  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
951  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
952 
955 
958 
959  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
960  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
961 
962  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
963  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
964  {75, 4, RailGraphics->gl75}};
965 
966  for(int x = 0; x < 40; x++)
967  {
968  SigTable[x] = TempSigTable[x];
969  }
970 
971  TSigElement TempSigTableThreeAspect[40] =
972  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
973  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
974 
977 
978  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
979  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
980 
981  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
982  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
983 
984  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
985  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
986  {75, 4, RailGraphics->gl75}};
987 
988  for(int x = 0; x < 40; x++)
989  {
990  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
991  }
992 
993  TSigElement TempSigTableTwoAspect[40] =
994  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
995  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
996 
997  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
998  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
999 
1000  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1001  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1002 
1003  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1004  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1005 
1006  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1007  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1008  {75, 4, RailGraphics->gl75}};
1009 
1010  for(int x = 0; x < 40; x++)
1011  {
1012  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1013  }
1014 
1015  TSigElement TempSigTableGroundSignal[40] =
1019 
1023 
1027 
1031 
1032  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1035 
1036  for(int x = 0; x < 40; x++)
1037  {
1038  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1039  }
1040 
1041 /*
1042  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1043  a single location. These are as follows:-
1044  Directly Adjacent = up, down, left or right - NOT diagonal.
1045  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1046  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1047  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1048 
1049  //t 76
1050  //b 77
1051  //l 78
1052  //r 79
1053  //c 96
1054  //v fb 129
1055  //h fb 130
1056  //v underpass 145
1057  //h underpass 146
1058  //n 131
1059 */
1060 
1061  int Tag76[25][3] =
1062  {{-1, 0, 96}, // c top plat
1063  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1064  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1065  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1066  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1067  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1068  {0, 0, 129}, {0, -1, 145}, // v up
1069  {0, 0, 145}};
1070 
1071  for(int x = 0; x < 25; x++)
1072  for(int y = 0; y < 3; y++)
1073  Tag76Array[x][y] = Tag76[x][y];
1074 
1075  int Tag77[25][3] =
1076  {{-1, 0, 96}, // c bot plat
1077  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1078  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1079  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1080  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1081  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1082  {0, 0, 129}, {0, 1, 145}, // v up
1083  {0, 0, 145}};
1084 
1085  for(int x = 0; x < 25; x++)
1086  for(int y = 0; y < 3; y++)
1087  Tag77Array[x][y] = Tag77[x][y];
1088 
1089  int Tag78[25][3] =
1090  {{-1, 0, 96}, // c left plat
1091  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1092  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1093  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1094  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1095  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1096  {0, 0, 130}, {-1, 0, 146}, // h up
1097  {0, 0, 146}};
1098 
1099  for(int x = 0; x < 25; x++)
1100  for(int y = 0; y < 3; y++)
1101  Tag78Array[x][y] = Tag78[x][y];
1102 
1103  int Tag79[25][3] =
1104  {{-1, 0, 96}, // c right plat
1105  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1106  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1107  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1108  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1109  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1110  {0, 0, 130}, {1, 0, 146}, // h up
1111  {0, 0, 146}};
1112 
1113  for(int x = 0; x < 25; x++)
1114  for(int y = 0; y < 3; y++)
1115  Tag79Array[x][y] = Tag79[x][y];
1116 
1117  int Tag96[28][3] =
1118  {{-1, 0, 96}, // c //concourse
1119  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1120  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1121  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1122  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1123  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1124  {0, -1, 129}, {1, 0, 130}, // h fb
1125  {-1, 0, 130}, {0, 1, 145}, // v up
1126  {0, -1, 145}, {1, 0, 146}, // h up
1127  {-1, 0, 146}};
1128 
1129  for(int x = 0; x < 28; x++)
1130  for(int y = 0; y < 3; y++)
1131  Tag96Array[x][y] = Tag96[x][y];
1132 
1133  int Tag129[8][3] = // vert fb
1134  {{0, -1, 96}, // c
1135  {0, -1, 77}, // b
1136  {0, -1, 129}, // v fb
1137 
1138  {0, 1, 96}, // c
1139  {0, 1, 76}, // t
1140  {0, 1, 129}, // v fb
1141 
1142  {0, 0, 76}, // t
1143  {0, 0, 77}}; // b
1144 
1145  for(int x = 0; x < 8; x++)
1146  for(int y = 0; y < 3; y++)
1147  Tag129Array[x][y] = Tag129[x][y];
1148 
1149  int Tag145[8][3] = // vert up
1150  {{0, -1, 96}, // c
1151  {0, -1, 77}, // b
1152  {0, -1, 145}, // v fb
1153 
1154  {0, 1, 96}, // c
1155  {0, 1, 76}, // t
1156  {0, 1, 145}, // v fb
1157 
1158  {0, 0, 76}, // t
1159  {0, 0, 77}}; // b
1160 
1161  for(int x = 0; x < 8; x++)
1162  for(int y = 0; y < 3; y++)
1163  Tag145Array[x][y] = Tag145[x][y];
1164 
1165  int Tag130[8][3] = // hor fb
1166  {{-1, 0, 96}, // c
1167  {-1, 0, 79}, // r
1168  {-1, 0, 130}, // h fb
1169 
1170  {1, 0, 96}, // c
1171  {1, 0, 78}, // l
1172  {1, 0, 130}, // h fb
1173 
1174  {0, 0, 78}, // l
1175  {0, 0, 79}}; // r
1176 
1177  for(int x = 0; x < 8; x++)
1178  for(int y = 0; y < 3; y++)
1179  Tag130Array[x][y] = Tag130[x][y];
1180 
1181  int Tag146[8][3] = // hor up
1182  {{-1, 0, 96}, // c
1183  {-1, 0, 79}, // r
1184  {-1, 0, 146}, // h fb
1185 
1186  {1, 0, 96}, // c
1187  {1, 0, 78}, // l
1188  {1, 0, 146}, // h fb
1189 
1190  {0, 0, 78}, // l
1191  {0, 0, 79}}; // r
1192 
1193  for(int x = 0; x < 8; x++)
1194  for(int y = 0; y < 3; y++)
1195  Tag146Array[x][y] = Tag146[x][y];
1196 
1197  int Tag131[4][3] =
1198  {{-1, 0, 131}, // n
1199  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1200 
1201  for(int x = 0; x < 4; x++)
1202  for(int y = 0; y < 3; y++)
1203  Tag131Array[x][y] = Tag131[x][y];
1204 
1205  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1206  {0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1207  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1208  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1209  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1210  140, 144, 145, 146};
1211 
1212  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1213  {0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1214  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1215  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1216  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1217  141, 144, 145, 146};
1218 
1219  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1220  {0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1221  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1222  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1223  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1224  141, 144, 146, 145};
1225 
1226  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1227  {0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1228  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1229  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1230  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1231  140, 144, 146, 145};
1232 
1233  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1234  {
1235  FlipArray[x] = InternalFlipArray[x];
1236  MirrorArray[x] = InternalMirrorArray[x];
1237  RotRightArray[x] = InternalRotRightArray[x];
1238  RotLeftArray[x] = InternalRotLeftArray[x];
1239  }
1240 }
1241 
1242 // ---------------------------------------------------------------------------
1244 {
1245 // delete TrackVectorPtr;
1246 // delete FixedTrackArrayPtr;
1247  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1248 
1249  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1250  {
1251  delete UGMIt->second;
1252  UGMIt++;
1253  }
1254  delete GapFlashGreen;
1255  delete GapFlashRed;
1256  // all the rest are cleared by the relevant automatic destructors
1257 }
1258 
1259 // ---------------------------------------------------------------------------
1260 
1262 {
1263  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1264  {
1265 // loc 0 not used, set to bmSolidBgnd
1269 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1289 
1290  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1291  {
1292 // loc 0 not used, set to smSolidBgnd
1296 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1315  RailGraphics->smTransparent, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1316  };
1317 
1318 // track types
1319  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1320  {Erase, // 1 0
1321  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1322  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1323  Crossover, Crossover, // 2 15-16
1324  Unused, // 17 (was for text in earlier development) //1 17
1327  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1331  Platform, Platform, Platform, Platform, // 4 76-79
1334  Concourse, // 1 96
1337  Simple, Simple, Simple, Simple, // 4 125-128
1338  FootCrossing, FootCrossing, // 2 129-130
1339  NamedNonStationLocation, // 1 131
1340  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1341  Simple, Simple, Simple, Simple, // 4 140-143
1342  LevelCrossing, // 1 144
1343  FootCrossing, FootCrossing // 2 145 & 146
1344  };
1345 
1346 // links
1347  int Links[FirstUnusedSpeedTagNumber][4] =
1348  {{-1, -1, -1, -1}, // erase element
1349  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1350  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1351 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1352  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1353  {-1, -1, -1, -1}, // unused
1354  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1355  {2, 7, -1, -1}, // simple
1356  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8
1357  }, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1358 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1359 // (or right diverging if no straight)
1360  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1361  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6
1362  }, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1363  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1
1364  }, // buffers - position 0 = buffer
1365  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1
1366  }, // signals (need Config to determine signal end, see below)
1367  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1368  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1
1369  }, // continuation - position 0 = continuation
1370  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1
1371  }, // gapjump - position 0 = gap
1372  {-1, -1, -1, -1}, // Concourse
1373  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1374  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1375  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1376  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1377  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1378  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1379  {-1, -1, -1, -1}, // NamedNonStationLocation
1380  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1381 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1382  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1383  {-1, -1, -1, -1}, // level crossing
1384  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1385  };
1386 
1388  {{NotSet, NotSet, NotSet, NotSet}, // unused
1392  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1394  {NotSet, NotSet, NotSet, NotSet}, // unused
1398  {Connection, Connection, NotSet, NotSet}, // simple
1402  {Lead, Trail, Lead, Trail}, // points
1404  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1413  }, // signals (signal at exit end in forward direction)
1417  }, // continuation
1420  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1429  {Connection, Connection, NotSet, NotSet}, // Arrows
1431  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1433  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1435  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1436  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1437  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1438  };
1439 
1440  for(int x = 0; x < 17; x++)
1441  {
1442  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1443  }
1444  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1445 // 17 was the old text value so don't want any graphics (now disused)
1446  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1447  {
1448  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1449  }
1450 }
1451 
1452 // ---------------------------------------------------------------------------
1453 TGraphicElement::TGraphicElement(): OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1454  ExistingGraphicLoaded(false), Width(16), Height(16)
1455 {
1456  OriginalGraphic = new Graphics::TBitmap;
1457  OriginalGraphic->PixelFormat = pf8bit;
1458  OriginalGraphic->Width = Width;
1459  OriginalGraphic->Height = Height;
1460  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1461 }
1462 
1463 // ---------------------------------------------------------------------------
1464 
1465 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn): OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1466  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1467 {
1468  OriginalGraphic = new Graphics::TBitmap;
1469  OriginalGraphic->PixelFormat = pf8bit;
1470  OriginalGraphic->Width = Width;
1471  OriginalGraphic->Height = Height;
1472  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1473 }
1474 
1475 // ---------------------------------------------------------------------------
1476 
1478 {
1479  delete OriginalGraphic;
1480 }
1481 
1482 // ---------------------------------------------------------------------------
1483 
1484 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1485 {
1486  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1487  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1488  VPos = VPosIn;
1489  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1490 
1491  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1492  SourceRect.init(Left, Top, Left + Width, Top + Height);
1493  ScreenSourceSet = true;
1494  Utilities->CallLogPop(422);
1495 }
1496 
1497 // ---------------------------------------------------------------------------
1498 
1500 {
1501  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1502  if(!OverlayLoaded)
1503  {
1504  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1505  }
1506  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1507  {
1508  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1509  }
1510  if(!ScreenSourceSet)
1511  {
1512  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1513  }
1514  if(ExistingGraphicLoaded) // can only call one of the load functions
1515  {
1516  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1517  }
1518  if(OverlayPlotted) // don't load from screen if overlay plotted
1519  {
1520  Utilities->CallLogPop(775);
1521  return;
1522  }
1523  TRect DestRect(0, 0, Width, Height);
1524 
1526  OriginalLoaded = true;
1527  ScreenGraphicLoaded = true;
1528  Utilities->CallLogPop(423);
1529 }
1530 
1531 // ---------------------------------------------------------------------------
1532 
1533 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1534 /*
1535  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1536 */
1537 {
1538  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1539  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1540  if(!OverlayLoaded)
1541  {
1542  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1543  }
1544  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1545  {
1546  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1547  }
1548  if(ScreenGraphicLoaded) // can only call one of the load functions
1549  {
1550  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1551  }
1552  Width = WidthIn;
1553  Height = HeightIn;
1554  OriginalGraphic->Width = Width;
1555  OriginalGraphic->Height = Height;
1556  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1557  VPos += VOffset;
1558  TRect DestRect(0, 0, Width, Height);
1559 
1560  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1561  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1562  OriginalLoaded = true;
1563  ExistingGraphicLoaded = true;
1564  Utilities->CallLogPop(424);
1565 }
1566 
1567 // ---------------------------------------------------------------------------
1568 
1569 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1570 {
1571  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1572  OverlayGraphic = Overlay;
1573  OverlayLoaded = true;
1574  Utilities->CallLogPop(425);
1575 }
1576 
1577 // ---------------------------------------------------------------------------
1578 
1580 {
1581  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1582  if(!OverlayLoaded)
1583  {
1584  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1585  }
1586  if(!OverlayPlotted)
1587  {
1588  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1589  Disp->Update();
1590  OverlayPlotted = true;
1591  }
1592  Utilities->CallLogPop(426);
1593 }
1594 
1595 // ---------------------------------------------------------------------------
1596 
1598 {
1599  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1600  if(OverlayPlotted)
1601  {
1602  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1603  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1604  {
1605  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1606  }
1607  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1608  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1609  OverlayPlotted = false;
1610  }
1611  Utilities->CallLogPop(427);
1612 }
1613 
1614 // ---------------------------------------------------------------------------
1615 
1617 {
1618  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1619  bool TrackPresent = false;
1620 
1621  if(InactiveTrackVector.size() != 0)
1622  {
1623  Utilities->CallLogPop(1333);
1624  return false;
1625  }
1626  else if(TrackVector.size() == 0)
1627  {
1628  Utilities->CallLogPop(1334);
1629  return true;
1630  }
1631  else
1632  {
1633  for(unsigned int x = 0; x < TrackVector.size(); x++)
1634  {
1635  if((TrackVector.at(x).SpeedTag != 0))
1636  TrackPresent = true;
1637  }
1638  }
1639  Utilities->CallLogPop(1335);
1640  return !TrackPresent;
1641 }
1642 
1643 // ---------------------------------------------------------------------------
1644 
1645 bool TTrack::NoActiveTrack(int Caller)
1646 {
1647  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1648  bool TrackPresent = false;
1649 
1650  if(TrackVector.size() == 0)
1651  {
1652  Utilities->CallLogPop(1582);
1653  return true;
1654  }
1655  else
1656  {
1657  for(unsigned int x = 0; x < TrackVector.size(); x++)
1658  {
1659  if((TrackVector.at(x).SpeedTag != 0))
1660  TrackPresent = true;
1661  break;
1662  }
1663  }
1664  Utilities->CallLogPop(1583);
1665  return !TrackPresent;
1666 }
1667 
1668 // ---------------------------------------------------------------------------
1669 
1670 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
1671 {
1672  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
1673  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
1674  TrackEraseSuccessfulFlag = false;
1675 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
1676 // since have to match platforms as well as track
1677 // used to set TrackFinished to false if an element erased
1678 
1679  ErasedTrackVectorPosition = -1; // marker for no element erased
1680  AnsiString SName = "", ErrorString;
1682  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
1683  TTrackMapIterator TrackMapPtr;
1684  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
1685 
1686  if(TrackVector.size() != 0)
1687  {
1688  TrackMapKeyPair.first = HLocInput;
1689  TrackMapKeyPair.second = VLocInput;
1690  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
1691  if(TrackMapPtr != TrackMap.end())
1692  {
1693  bool FoundFlag;
1694  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
1695  if(FoundFlag) // should find it as it's in the map
1696  {
1697  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
1698  {
1699  SName = TrackElementAt(1, VecPos).LocationName;
1700  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
1701  if(ErrorString != "")
1702  {
1703  throw Exception(ErrorString + " for EraseTrackElement 1");
1704  }
1705  LocationNameMultiMap.erase(SNIt);
1706  }
1707 
1708  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
1709  // ensure erase vector element before map element as iterator no longer valid after a map erase
1710  TrackMap.erase(TrackMapPtr);
1711  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
1712  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1714  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
1715  if(SName != "")
1716  {
1717  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
1718  int HPos, VPos;
1719  if(TextHandler->FindText(1, SName, HPos, VPos))
1720  {
1721  if(TextHandler->TextErase(5, HPos, VPos, SName))
1722  {;
1723  } // condition not used
1724  }
1725  }
1726  ErasedTrackVectorPosition = VecPos;
1727  TrackEraseSuccessfulFlag = true;
1728  }
1729  }
1730  }
1731 
1732  if(InactiveTrackVector.size() != 0)
1733  {
1734  unsigned int VecPos;
1735  InactiveTrackMapKeyPair.first = HLocInput;
1736  InactiveTrackMapKeyPair.second = VLocInput;
1737  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
1738  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
1739  {
1740  SName = "";
1741  VecPos = InactiveTrack2MultiMapIterator->second;
1742  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
1743  {
1744  SName = InactiveTrackElementAt(1, VecPos).LocationName;
1745  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
1746  if(ErrorString != "")
1747  {
1748  throw Exception(ErrorString + " for EraseTrackElement 2A");
1749  }
1750  LocationNameMultiMap.erase(SNIt);
1751  }
1752  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
1753  // ensure erase vector element before map element as iterator no longer valid after a map erase
1754  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
1755  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
1756  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1758  TrackEraseSuccessfulFlag = true;
1759  if(SName != "")
1760  {
1761  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
1762  int HPos, VPos;
1763  if(TextHandler->FindText(2, SName, HPos, VPos))
1764  {
1765  if(TextHandler->TextErase(6, HPos, VPos, SName))
1766  {;
1767  } // condition not used
1768  }
1769  }
1770  }
1771 
1772  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
1773  {
1774  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
1775  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
1776  {
1777  SName = "";
1778  VecPos = InactiveTrack2MultiMapIterator->second;
1779  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
1780  {
1781  SName = InactiveTrackElementAt(3, VecPos).LocationName;
1782  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
1783  if(ErrorString != "")
1784  {
1785  throw Exception(ErrorString + " for EraseTrackElement 2B");
1786  }
1787  LocationNameMultiMap.erase(SNIt);
1788  }
1789  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
1790  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
1791  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1793  if(SName != "")
1794  {
1795  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
1796  int HPos, VPos;
1797  if(TextHandler->FindText(3, SName, HPos, VPos))
1798  {
1799  if(TextHandler->TextErase(7, HPos, VPos, SName))
1800  {;
1801  } // condition not used
1802  }
1803  }
1804  }
1805  }
1806  }
1807  if(TrackEraseSuccessfulFlag)
1808  {
1809  CalcHLocMinEtc(2);
1810  SetTrackFinished(false);
1811  }
1812  if(InternalChecks)
1813  {
1814  CheckMapAndTrack(1); // test
1815  CheckMapAndInactiveTrack(1); // test
1816  CheckLocationNameMultiMap(6); // test
1817  }
1818  Utilities->CallLogPop(428);
1819 }
1820 
1821 // ---------------------------------------------------------------------------
1822 
1823 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
1824  // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
1825  // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
1826  // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
1827 {
1828  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
1829  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
1830  bool PlatAllowedFlag = false;
1831 
1832  TrackLinkingRequiredFlag = false;
1833 /*
1834  Not erase, that covered separately.
1835  First check if Current SpeedButton assigned, then check if a platform and only
1836  permit if an appropriate trackpiece already there & not a same platform there.
1837  - can't enter a platform without track first.
1838  Then for non-platforms, check if a track piece already present at location &
1839  reject if so.
1840 */
1841 
1842  TLocationNameMultiMapEntry LocationNameEntry;
1843 
1844  LocationNameEntry.first = "";
1845  if(CurrentTag == 0)
1846  {
1847  Utilities->CallLogPop(429);
1848  return; // not assigned yet
1849  }
1850 
1851  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
1852 
1853  TempTrackElement.HLoc = HLocInput;
1854  TempTrackElement.VLoc = VLocInput;
1855  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
1856 // new at version 0.6 - set signal aspect depending on build mode
1857 
1858  if(TempTrackElement.TrackType == SignalPost)
1859  {
1860  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
1861  // pasting a SignalPost can only have values 1 to 4
1862  {
1864  {
1865  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
1866  }
1868  {
1869  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
1870  }
1872  {
1873  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
1874  }
1875  else
1876  {
1877  TempTrackElement.SigAspect = TTrackElement::FourAspect;
1878  }
1879  }
1880  else if(Aspect == 1)
1881  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
1882  else if(Aspect == 2)
1883  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
1884  else if(Aspect == 3)
1885  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
1886  else
1887  TempTrackElement.SigAspect = TTrackElement::FourAspect;
1888  }
1889 
1890  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
1891  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
1892  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
1893  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
1894 
1895  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
1896  {
1898  NonStationOrLevelCrossingPresent = true;
1899  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
1900  NonStationOrLevelCrossingPresent = true;
1901  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
1902  PlatformPresent = true;
1903  // no need to check IMPair.second since if that exists it is because .first is a platform
1904  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
1905  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
1906  }
1907 
1908 // check platforms
1909  if(TempTrackElement.TrackType == Platform)
1910  {
1911  if(FoundFlag) // active track element already there
1912  {
1913  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
1914  {;
1915  }
1916  // same platform type already there so above keeps PlatAllowedFlag false
1917  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
1918  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
1919  {
1920  PlatAllowedFlag = true;
1921  }
1922  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
1923  {
1924  PlatAllowedFlag = true;
1925  }
1926  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
1927  {
1928  PlatAllowedFlag = true;
1929  }
1930  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
1931  {
1932  PlatAllowedFlag = true;
1933  }
1934  if(PlatAllowedFlag)
1935  {
1936  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
1937  TrackPush(1, TempTrackElement);
1938  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
1939  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
1940  // Must be called AFTER TrackPush
1941  // No need to plot the element - Clearand ... called after this function called
1942  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
1943  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
1944 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
1945 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
1946 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
1947  if(InternalChecks)
1948  {
1949  CheckMapAndInactiveTrack(5); // test
1950  CheckLocationNameMultiMap(4); // test
1951  }
1952  Utilities->CallLogPop(430);
1953  return;
1954  }
1955  } // if(FoundFlag)
1956  Utilities->CallLogPop(431);
1957  return;
1958  } // if platform
1959 
1960 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
1961  if(TempTrackElement.TrackType == NamedNonStationLocation)
1962  {
1963  if((FoundFlag && (NameAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
1964  (!FoundFlag && !InactiveFoundFlag))
1965  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
1966  {
1967  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
1968  TrackPush(2, TempTrackElement);
1969  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
1970  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
1971  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
1972  {
1973 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
1974 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
1975 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
1976  }
1977  if(InternalChecks)
1978  {
1979  CheckMapAndInactiveTrack(11); // test
1980  CheckLocationNameMultiMap(12); // test
1981  }
1982  Utilities->CallLogPop(432);
1983  return;
1984  }
1985  else
1986  {
1987  Utilities->CallLogPop(433);
1988  return;
1989  }
1990  }
1991 
1992 // check if a level crossing - OK if placed on a plain straight track
1993  if(TempTrackElement.TrackType == LevelCrossing)
1994  {
1995  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
1996  {
1997  TrackPush(11, TempTrackElement);
1998  PlotRaisedLinkedLevelCrossingBarriers(0, TrackVector.at(VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
1999 // no need for reference to LC element as can't be open
2000  TrackLinkingRequiredFlag = true;
2001  Utilities->CallLogPop(1907);
2002  return;
2003  }
2004  else
2005  {
2006  Utilities->CallLogPop(1906);
2007  return; // was a level crossing but can't place it for some reason
2008  }
2009  }
2010 
2011 // check if another element already there
2012  else if(FoundFlag || InactiveFoundFlag)
2013  {
2014  Utilities->CallLogPop(434);
2015  return; // something already there (active or inactive track)
2016  }
2017 
2018 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2019 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2020 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2021 // do this after pushed into vector so that can use EnterLocationName
2022 
2023  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2024  {
2025  TrackPush(3, TempTrackElement);
2026  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2027  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2028  }
2029  else if(TempTrackElement.TrackType == Points)
2030  {
2031  TrackPush(4, TempTrackElement);
2032  bool BothPointFillets = true;
2033  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2034  }
2035  else if(TempTrackElement.TrackType == SignalPost)
2036  {
2037  TrackPush(10, TempTrackElement);
2038  PlotSignal(12, TempTrackElement, Display);
2039  }
2040  else
2041  {
2042  TrackPush(5, TempTrackElement);
2043  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2044  }
2045  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2046  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2047  if(InternalChecks)
2048  {
2049  CheckMapAndTrack(2); // test
2050  CheckMapAndInactiveTrack(2); // test
2051  CheckLocationNameMultiMap(5); // test
2052  }
2053  Utilities->CallLogPop(2062);
2054 }
2055 
2056 // ---------------------------------------------------------------------------
2057 
2058 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2059  bool InternalChecks)
2060  // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2061 {
2062  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2063  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2064  bool PlatAllowedFlag = false;
2065 
2066  TrackLinkingRequiredFlag = false;
2067  TLocationNameMultiMapEntry LocationNameEntry;
2068 
2069  LocationNameEntry.first = "";
2070  if(TempTrackElement.SpeedTag == 0)
2071  {
2072  Utilities->CallLogPop(2063);
2073  return; // not assigned yet
2074  }
2075 
2076  TempTrackElement.HLoc = HLocInput;
2077  TempTrackElement.VLoc = VLocInput;
2078  for(int x = 0; x < 4; x++) // unset any gaps
2079  {
2080  if(TempTrackElement.Config[x] == Gap)
2081  TempTrackElement.ConnLinkPos[x] = -1;
2082  TempTrackElement.Conn[x] = -1;
2083  }
2084  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2085 // new at version 0.6 - set signal aspect depending on build mode
2086  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2087  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2088 
2089  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2090  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2091  // for the active track element because these aren't set
2092  // if don't do this then get a mismatch error during map checks later
2093 
2094  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2095 
2096  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2097  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2098 
2099  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2100  {
2101  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2102  NonStationOrLevelCrossingPresent = true;
2103  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2104  NonStationOrLevelCrossingPresent = true;
2105  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2106  PlatformPresent = true;
2107  // no need to check IMPair.second since if that exists it is because .first is a platform
2108  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2109  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2110  }
2111 
2112 // check platforms
2113  if(TempTrackElement.TrackType == Platform)
2114  {
2115  if(FoundFlag) // active track element already there
2116  {
2117  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2118  {;
2119  }
2120  // same platform type already there so above keeps PlatAllowedFlag false
2121  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2122  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2123  {
2124  PlatAllowedFlag = true;
2125  }
2126  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2127  {
2128  PlatAllowedFlag = true;
2129  }
2130  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2131  {
2132  PlatAllowedFlag = true;
2133  }
2134  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2135  {
2136  PlatAllowedFlag = true;
2137  }
2138  if(PlatAllowedFlag)
2139  {
2140  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2141  TrackPush(12, TempTrackElement);
2142 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2143  {
2144  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2145  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2146  }
2147  // Must be called AFTER TrackPush
2148 // No need to plot the element - Clearand ... called after this function called
2149  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2150  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2151 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2152 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2153 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2154  if(InternalChecks)
2155  {
2156  CheckMapAndInactiveTrack(12); // test
2157  CheckLocationNameMultiMap(20); // test
2158  }
2159  Utilities->CallLogPop(2064);
2160  return;
2161  }
2162  } // if(FoundFlag)
2163  Utilities->CallLogPop(2065);
2164  return;
2165  } // if platform
2166 
2167 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2168  if(TempTrackElement.TrackType == NamedNonStationLocation)
2169  {
2170  if((FoundFlag && (NameAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2171  (!FoundFlag && !InactiveFoundFlag))
2172  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2173  {
2174  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2175  TrackPush(13, TempTrackElement);
2176 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2177  {
2178  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2179  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2180  }
2181  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2182  {
2183 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2184 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2185 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2186  }
2187  if(InternalChecks)
2188  {
2189  CheckMapAndInactiveTrack(13); // test
2190  CheckLocationNameMultiMap(21); // test
2191  }
2192  Utilities->CallLogPop(2066);
2193  return;
2194  }
2195  else
2196  {
2197  Utilities->CallLogPop(2067);
2198  return;
2199  }
2200  }
2201 
2202 // check if a level crossing - OK if placed on a plain straight track
2203  if(TempTrackElement.TrackType == LevelCrossing)
2204  {
2205  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2206  {
2207  TrackPush(14, TempTrackElement);
2208  PlotRaisedLinkedLevelCrossingBarriers(3, TrackVector.at(VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2209 // no need for reference to LC element as can't be open
2210  TrackLinkingRequiredFlag = true;
2211  Utilities->CallLogPop(2068);
2212  return;
2213  }
2214  else
2215  {
2216  Utilities->CallLogPop(2069);
2217  return; // was a level crossing but can't place it for some reason
2218  }
2219  }
2220 
2221 // check if another element already there
2222  else if(FoundFlag || InactiveFoundFlag)
2223  {
2224  Utilities->CallLogPop(2070);
2225  return; // something already there (active or inactive track)
2226  }
2227 
2228 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2229 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2230 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2231 // do this after pushed into vector so that can use EnterLocationName
2232 
2233  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2234  {
2235  TrackPush(15, TempTrackElement);
2236  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2237  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2238  }
2239  else if(TempTrackElement.TrackType == Points)
2240  {
2241  TrackPush(16, TempTrackElement);
2242  bool BothPointFillets = true;
2243  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2244  }
2245  else if(TempTrackElement.TrackType == SignalPost)
2246  {
2247  TrackPush(17, TempTrackElement);
2248  PlotSignal(14, TempTrackElement, Display);
2249  }
2250  else
2251  {
2252  TrackPush(18, TempTrackElement);
2253  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2254  }
2255  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2256  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2257  if(InternalChecks)
2258  {
2259  CheckMapAndTrack(12); // test
2260  CheckMapAndInactiveTrack(14); // test
2261  CheckLocationNameMultiMap(22); // test
2262  }
2263  Utilities->CallLogPop(2071);
2264 }
2265 
2266 // ---------------------------------------------------------------------------
2267 
2268 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2269  // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2270  // return bool = true for success
2271  // LocError = true for location error & HLoc & VLoc to be inverted
2272 {
2273  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2274  LocError = false;
2275  SetTrackFinished(false);
2276  if(TrackVector.size() == 0)
2277  {
2278  Utilities->CallLogPop(437);
2279  return false;
2280  }
2281  if(GapsUnset(7))
2282  {
2283  if(GiveMessages)
2284  ShowMessage("Gaps must be set before track can be validated");
2285  Utilities->CallLogPop(1135);
2286  return false;
2287  }
2288 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2289 // returns true for any unset gaps
2291  {
2292  // can keep this exception as protected by the GapsUnset call above
2293  throw Exception("Error, gaps unset when TryToConnectTrack called");
2294  }
2296  CheckGapMap(1); // test
2297 // Gap connections now securely defined
2298 
2299  CheckMapAndTrack(8); // test
2300 
2301 // Perform a pre-check prior to TrackMap being compiled
2302  if(GiveMessages)
2303  {
2304  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2305  {
2306  Utilities->CallLogPop(439);
2307  return false;
2308  }
2309  }
2310  else
2311  {
2312  if(!LinkTrackNoMessages(1, false))
2313  {
2314  Utilities->CallLogPop(1131);
2315  return false;
2316  }
2317  }
2318 
2319 // here if pre-check successful
2320  if(!RepositionAndMapTrack(0))
2321  {
2322  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2323  Utilities->CallLogPop(1138);
2324  return false;
2325  }
2326 // now perform the final assembly - FinalCall = true
2327  if(GiveMessages)
2328  {
2329  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2330  {
2331  Utilities->CallLogPop(1116);
2332  return false;
2333  }
2334  }
2335  else
2336  {
2337  if(!LinkTrackNoMessages(2, true))
2338  {
2339  Utilities->CallLogPop(1132);
2340  return false;
2341  }
2342  }
2343 
2344 // success
2345 
2346  PopulateLCVector(0);
2347  CheckGapMap(2); // test
2348  CheckMapAndTrack(3); // test
2349  CheckMapAndInactiveTrack(3); // test
2350  CheckLocationNameMultiMap(9); // test
2351  SetTrackFinished(true);
2352 
2353 // Build ContinuationNameMap
2354  std::pair<AnsiString, char>TempMapPair;
2355 
2356  ContinuationNameMap.clear();
2357  for(int x = 0; x < Track->TrackVectorSize(); x++)
2358  {
2359  if((Track->TrackVector.at(x).TrackType == Continuation) && (Track->TrackVector.at(x).ActiveTrackElementName != ""))
2360  {
2361  TempMapPair.first = Track->TrackVector.at(x).ActiveTrackElementName;
2362  TempMapPair.second = 'x'; // unused
2363  ContinuationNameMap.insert(TempMapPair);
2364  }
2365  }
2366  Utilities->CallLogPop(440);
2367  return true;
2368 }
2369 
2370 // ---------------------------------------------------------------------------
2371 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2372  // unused - too time-consuming - double brute force search
2373 {
2374  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2375  int NewHLoc, NewVLoc;
2376  bool ConnectionFoundFlag, LinkFoundFlag;
2377 
2378  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2379  {
2380  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2381  {
2382  if(TrackVector.at(x).Link[y] <= 0)
2383  continue; // no link
2384  if(TrackVector.at(x).Config[y] == End)
2385  continue; // buffer or continuation
2386  if(TrackVector.at(x).Config[y] == Gap)
2387  continue; // gap jump
2388  // get required H & V for track element joining link 'y'
2389  NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
2390  NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
2391  // find track element if present
2392  ConnectionFoundFlag = false;
2393  for(unsigned int z = 0; z < TrackVector.size(); z++)
2394  {
2395 // if(TrackElementAt(5, z).TrackType == Platform)
2396 // continue; //skip platforms
2397  if((TrackVector.at(z).HLoc == NewHLoc) && (TrackVector.at(z).VLoc == NewVLoc))
2398  {
2399  ConnectionFoundFlag = true;
2400  // find connecting link in the newly found track element if there is one
2401  LinkFoundFlag = false;
2402  for(unsigned int a = 0; a < 4; a++)
2403  {
2404  if(TrackVector.at(z).Link[a] == (10 - TrackVector.at(x).Link[y]))
2405  {
2406  LinkFoundFlag = true;
2407  }
2408  }
2409  // if there isn't a corresponding link set the invert values for the offending element
2410  if(!LinkFoundFlag)
2411  {
2412  HLoc = TrackVector.at(x).HLoc;
2413  VLoc = TrackVector.at(x).VLoc;
2414  Utilities->CallLogPop(441);
2415  return true;
2416  }
2417  break; // success, so break out of 'z' loop
2418  } // if((TrackVector.at(z).HLoc== NewHLoc) &&....
2419  } // for z...
2420  // if there isn't a connection set the invert values for the offending element
2421  if(!ConnectionFoundFlag)
2422  {
2423  HLoc = TrackVector.at(x).HLoc;
2424  VLoc = TrackVector.at(x).VLoc;
2425  Utilities->CallLogPop(442);
2426  return true;
2427  }
2428  } // for y....
2429  } // for x...
2430  Utilities->CallLogPop(443);
2431  return false; // all OK
2432 }
2433 
2434 // ---------------------------------------------------------------------------
2435 
2436 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2437 {
2438  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2439  TrackElement.LogTrack(0));
2440  bool FoundFlag;
2441 
2442  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2443  if(FoundFlag)
2444  TrackElement = TrackVector.at(Position);
2445  Utilities->CallLogPop(444);
2446  return FoundFlag;
2447 }
2448 
2449 // ---------------------------------------------------------------------------
2450 
2452 {
2453  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2454  if(NextTrackElementPtr >= TrackVector.end())
2455  {
2456  Utilities->CallLogPop(1336);
2457  return false;
2458  }
2459  Next = *NextTrackElementPtr;
2461  Utilities->CallLogPop(1337);
2462  return true;
2463 }
2464 
2465 // ---------------------------------------------------------------------------
2466 
2468 {
2469  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2471  {
2472  Utilities->CallLogPop(1338);
2473  return false;
2474  }
2475  Next = *NextTrackElementPtr;
2477  Utilities->CallLogPop(1339);
2478  return true;
2479 }
2480 
2481 // ---------------------------------------------------------------------------
2482 
2483 int TTrack::NumberOfGaps(int Caller)
2484 
2485 {
2486  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2487  int Count = 0;
2488 
2489  if(TrackVector.size() == 0)
2490  {
2491  Utilities->CallLogPop(1340);
2492  return 0;
2493  }
2494  for(unsigned int x = 0; x < TrackVector.size(); x++)
2495  {
2496  if(TrackVector.at(x).TrackType == GapJump)
2497  Count++;
2498  }
2499  Utilities->CallLogPop(1341);
2500  return Count;
2501 }
2502 
2503 // ---------------------------------------------------------------------------
2505  // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2506  // returns true for any unset gaps
2507 {
2508  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2509  bool UnsetGaps = false;
2510 
2511  if(TrackVector.size() == 0)
2512  {
2513  Utilities->CallLogPop(445);
2514  return false;
2515  }
2516  for(unsigned int x = 0; x < TrackVector.size(); x++)
2517  {
2518  if(TrackVector.at(x).TrackType != GapJump)
2519  {
2520  for(unsigned int y = 0; y < 4; y++)
2521  {
2522  TrackVector.at(x).Conn[y] = -1;
2523  TrackVector.at(x).ConnLinkPos[y] = -1;
2524  }
2525  }
2526  else // GapJump
2527  {
2528 // int tempint = TrackVector.at(x).Conn[0);
2529 
2530  if(TrackVector.at(x).Conn[0] == -1) // unset if -1
2531  {
2532  for(unsigned int y = 0; y < 4; y++)
2533  {
2534  TrackVector.at(x).Conn[y] = -1;
2535  TrackVector.at(x).ConnLinkPos[y] = -1;
2536  }
2537  UnsetGaps = true;
2538  continue; // to next 'x'
2539  }
2540  else // set, but may not have matching element, or that element may not be set
2541  {
2542  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2543  {
2544  TrackVector.at(x).Conn[y] = -1;
2545  TrackVector.at(x).ConnLinkPos[y] = -1;
2546  }
2547 
2548  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
2549  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
2550  {
2551  for(unsigned int y = 0; y < 4; y++)
2552  {
2553  TrackVector.at(x).Conn[y] = -1;
2554  TrackVector.at(x).ConnLinkPos[y] = -1;
2555  }
2556  UnsetGaps = true;
2557  continue; // to next 'x'
2558  }
2559 // here if gap connection is itself a GapJump
2560  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
2561  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
2562  // if not clear Conns & CLks & reset Lk[0]
2563  {
2564  for(unsigned int y = 0; y < 4; y++)
2565  {
2566  TrackVector.at(x).Conn[y] = -1;
2567  TrackVector.at(x).ConnLinkPos[y] = -1;
2568  }
2569  UnsetGaps = true;
2570  continue; // to next 'x'
2571  }
2572 // here if gap connection itself points back to 'x' so these two GapJumps match properly
2573 // hence no more action needed on these Conns & CLks
2574  }
2575  } // else //gap jump
2576  } // for x...
2577  Utilities->CallLogPop(446);
2578  return UnsetGaps;
2579 }
2580 
2581 // ---------------------------------------------------------------------------
2582 
2583 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
2584 {
2585 // VecFile already open and its pointer at right place on calling
2586  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
2587  int TempInt;
2588 
2589  TrackClear(1);
2590 // load track elements
2591  int NumberOfActiveElements = 0;
2592 
2593  GraphicsFollow = false;
2594  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
2595  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
2596 
2597  if(MarkerString[MarkerString.Length()] == '1')
2598  {
2599  GraphicsFollow = true;
2600  }
2601  for(int x = 0; x < NumberOfActiveElements; x++)
2602  {
2603  VecFile >> TempInt; // TrackVectorNumber, not used
2604  VecFile >> TempInt; // SpeedTag
2605  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
2606  VecFile >> TempInt;
2607  TrackElement.HLoc = TempInt;
2608  VecFile >> TempInt;
2609  TrackElement.VLoc = TempInt;
2610  if(TrackElement.TrackType == GapJump)
2611  {
2612  VecFile >> TempInt;
2613  TrackElement.ConnLinkPos[0] = TempInt;
2614  VecFile >> TempInt;
2615  TrackElement.Conn[0] = TempInt;
2616  }
2617  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
2618  {
2619  VecFile >> TempInt;
2620  TrackElement.Attribute = TempInt;
2621  }
2622  if(TrackElement.TrackType == SignalPost)
2623  {
2624  VecFile >> TempInt;
2625  if(TempInt == 0)
2626  TrackElement.CallingOnSet = false;
2627  else
2628  TrackElement.CallingOnSet = true;
2629  }
2630  VecFile >> TempInt;
2631  TrackElement.Length01 = TempInt;
2632  VecFile >> TempInt;
2633  TrackElement.Length23 = TempInt;
2634  VecFile >> TempInt;
2635  if((TempInt != -1) && (TempInt < 10))
2636  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
2637  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
2638  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
2639  TrackElement.SpeedLimit01 = TempInt;
2640  VecFile >> TempInt;
2641  if((TempInt != -1) && (TempInt < 10))
2642  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
2643  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
2644  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
2645  TrackElement.SpeedLimit23 = TempInt;
2646 
2647  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
2648  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
2649  SetElementID(0, TrackElement);
2650  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
2651 // new for v0.6
2652  if(TrackElement.TrackType == SignalPost)
2653  {
2654  if(Marker[1] == '3')
2655  {
2656  TrackElement.SigAspect = TTrackElement::ThreeAspect;
2657  }
2658  else if(Marker[1] == '2')
2659  {
2660  TrackElement.SigAspect = TTrackElement::TwoAspect;
2661  }
2662  else if(Marker[1] == 'G')
2663  {
2664  TrackElement.SigAspect = TTrackElement::GroundSignal;
2665  }
2666  else
2667  {
2668  TrackElement.SigAspect = TTrackElement::FourAspect;
2669  }
2670  }
2671  if(TrackElement.SpeedTag != 0)
2672  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
2673  }
2674  int NumberOfInactiveElements = 0;
2675 
2676  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
2677  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
2678  for(int x = 0; x < NumberOfInactiveElements; x++)
2679  {
2680  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
2681  VecFile >> TempInt; // SpeedTag
2682  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
2683  VecFile >> TempInt;
2684  TrackElement.HLoc = TempInt;
2685  VecFile >> TempInt;
2686  TrackElement.VLoc = TempInt;
2687  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
2688  SetElementID(3, TrackElement);
2689  TrackPush(9, TrackElement);
2690  Utilities->LoadFileString(VecFile); // marker
2691  }
2692  bool LocError = false; // needed for TryToConnectTrack but not used
2693  int H = -1, V = -1; // needed for TryToConnectTrack but not used
2694 
2695  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
2696  {
2697  SetTrackFinished(true);
2698  }
2699  else
2700  {
2701  SetTrackFinished(false);
2702  }
2703 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
2704 // CheckMapAndInactiveTrack(8);
2705 // CheckLocationNameMultiMap(10);
2706  Utilities->CallLogPop(448);
2707 }
2708 
2709 // ---------------------------------------------------------------------------
2710 
2711 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
2712 {
2713 // VecFile already open and its pointer at right place on calling
2714  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
2715 // first int is number of graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
2716 // & load into UserGraphicItem then store in UserGraphicVector
2717  UserGraphicVector.clear();
2718  TUserGraphicItem UGI;
2719  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
2720 
2721  for(int x = 0; x < NumberOfGraphics; x++)
2722  {
2723  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
2724  UGI.HPos = Utilities->LoadFileInt(VecFile);
2725  UGI.VPos = Utilities->LoadFileInt(VecFile);
2726  UGI.Width = 0; // provisional value
2727  UGI.Height = 0; // provisional value
2728  UGI.UserGraphic = NULL; // provisional value
2729  UserGraphicVector.push_back(UGI);
2730  }
2731 // now load the map & set Width, Height & TPicture*
2732  bool FileError = false;
2733 
2734  for(int x = 0; x < NumberOfGraphics; x++)
2735  {
2736  if(FileError)
2737  {
2738  break; // otherwise keeps going round the loop
2739  }
2740  UGI = UserGraphicVectorAt(0, x);
2741  if(UserGraphicMap.empty()) // will be when x == 0 but not after
2742  {
2743  try
2744  {
2745 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
2746  UGME.first = UGI.FileName;
2747  UGME.second = new TPicture;
2748  UGME.second->LoadFromFile(UGME.first); // errors caught below
2749  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
2750  {
2751  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
2752  }
2753  UGI.UserGraphic = UGME.second;
2754  UGI.Width = UGI.UserGraphic->Width;
2755  UGI.Height = UGI.UserGraphic->Height;
2756  UserGraphicVectorAt(1, x) = UGI;
2757  }
2758  catch(const EInvalidGraphic &e)
2759  {
2760  //message already sent in CheckUserGraphics
2761  FileError = true;
2762  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
2763  if(!UserGraphicMap.empty())
2764  {
2765  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2766  {
2767  delete UGMIt->second;
2768  }
2769  UserGraphicMap.clear();
2770  }
2771  }
2772  catch(const Exception &e)
2773  {
2774  //message already sent in CheckUserGraphics
2775  FileError = true;
2776  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
2777  if(!UserGraphicMap.empty())
2778  {
2779  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2780  {
2781  delete UGMIt->second;
2782  }
2783  UserGraphicMap.clear();
2784  }
2785  }
2786  }
2787  else
2788  {
2789  bool FoundInMap = false;
2790  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2791  {
2792  if(UGI.FileName == UGMIt->first) // already exists in map
2793  {
2794  UGI.UserGraphic = UGMIt->second;
2795  UGI.Width = UGI.UserGraphic->Width;
2796  UGI.Height = UGI.UserGraphic->Height;
2797  UserGraphicVectorAt(2, x) = UGI;
2798  FoundInMap = true;
2799  break;
2800  }
2801  }
2802  if(!FoundInMap)
2803  {
2804  try
2805  {
2807  UGME.first = UGI.FileName;
2808  UGME.second = new TPicture;
2809  UGME.second->LoadFromFile(UGME.first); // errors caught below
2810  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
2811  {
2812  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
2813  }
2814  UGI.UserGraphic = UGME.second;
2815  UGI.Width = UGI.UserGraphic->Width;
2816  UGI.Height = UGI.UserGraphic->Height;
2817  UserGraphicVectorAt(3, x) = UGI;
2818  }
2819  catch(const EInvalidGraphic &e)
2820  {
2821  //message already sent in CheckUserGraphics
2822  FileError = true;
2823  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
2824  if(!UserGraphicMap.empty())
2825  {
2826  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2827  {
2828  delete UGMIt->second;
2829  }
2830  UserGraphicMap.clear();
2831  }
2832  }
2833  catch(const Exception &e)
2834  {
2835  //message already sent in CheckUserGraphics
2836  FileError = true;
2837  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
2838  if(!UserGraphicMap.empty())
2839  {
2840  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2841  {
2842  delete UGMIt->second;
2843  }
2844  UserGraphicMap.clear();
2845  }
2846  }
2847  }
2848  }
2849  }
2850  Utilities->CallLogPop(2167);
2851 }
2852 
2853 // ---------------------------------------------------------------------------
2854 
2855 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
2856 {
2857 // VecFile already open and its pointer at right place on calling
2858 // if GraphicsFollow true, then save Marker as **Active elements**1
2859 // save trackfinished flag
2860  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
2861  TTrackElement TrackElement, InactiveTrackElement;
2862 
2863 // save track elements
2864  Utilities->SaveFileInt(VecFile, TrackVector.size());
2865  if(GraphicsFollow)
2866  {
2867  VecFile << "**Active elements**1" << '\0' << '\n';
2868  }
2869  else
2870  {
2871  VecFile << "**Active elements**" << '\0' << '\n';
2872  }
2873  for(unsigned int x = 0; x < (TrackVector.size()); x++)
2874  {
2875  TrackElement = TrackVector.at(x);
2876  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
2877  VecFile << TrackElement.SpeedTag << '\n';
2878  VecFile << TrackElement.HLoc << '\n';
2879  VecFile << TrackElement.VLoc << '\n';
2880  if(TrackElement.TrackType == GapJump)
2881  {
2882  VecFile << TrackElement.ConnLinkPos[0] << '\n';
2883  VecFile << TrackElement.Conn[0] << '\n';
2884  }
2885  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
2886  {
2887  VecFile << TrackElement.Attribute << '\n';
2888  }
2889  if(TrackElement.TrackType == SignalPost)
2890  {
2891  if(TrackElement.CallingOnSet)
2892  VecFile << int(1) << '\n';
2893  else
2894  VecFile << int(0) << '\n';
2895  }
2896  VecFile << TrackElement.Length01 << '\n';
2897  VecFile << TrackElement.Length23 << '\n';
2898  VecFile << TrackElement.SpeedLimit01 << '\n';
2899  VecFile << TrackElement.SpeedLimit23 << '\n';
2900  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2901  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2902 // new for v0.6
2903  if(TrackElement.TrackType == SignalPost)
2904  {
2905  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
2906  {
2907  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2908  }
2909  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
2910  {
2911  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2912  }
2913  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
2914  {
2915  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2916  }
2917  else // 4 aspect
2918  {
2919  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2920  }
2921  }
2922  else
2923  {
2924  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2925  }
2926  }
2927 
2928  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
2929  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
2930  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
2931  {
2932  InactiveTrackElement = InactiveTrackVector.at(x);
2933  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
2934  VecFile << InactiveTrackElement.SpeedTag << '\n';
2935  VecFile << InactiveTrackElement.HLoc << '\n';
2936  VecFile << InactiveTrackElement.VLoc << '\n';
2937  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2938  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2939  }
2940  Utilities->CallLogPop(449);
2941 }
2942 
2943 // ---------------------------------------------------------------------------
2944 
2945 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
2946 {
2947 // VecFile already open and its pointer at right place on calling
2948 // check trackfinished flag
2949 // inactive elements follow immediately after active elements, no need to check for a marker between them
2950  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
2951  int TempInt;
2952 
2953  GraphicsFollow = false;
2954  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
2955  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
2956  {
2957  Utilities->CallLogPop(1513);
2958  return false;
2959  }
2960 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
2961  AnsiString MarkerString;
2962 
2963  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
2964  {
2965  Utilities->CallLogPop(1758);
2966  return false;
2967  }
2968  if(MarkerString[MarkerString.Length()] == '1')
2969  {
2970  GraphicsFollow = true;
2971  }
2972  for(int x = 0; x < NumberOfActiveElements; x++)
2973  {
2974  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
2975  {
2976  Utilities->CallLogPop(1759);
2977  return false;
2978  }
2979  VecFile >> TempInt;
2980  int SpeedTag = TempInt;
2981  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
2982  {
2983  Utilities->CallLogPop(1514);
2984  return false;
2985  }
2986  VecFile >> TempInt;
2987  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
2988  {
2989  Utilities->CallLogPop(1495);
2990  return false;
2991  }
2992  VecFile >> TempInt;
2993  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
2994  {
2995  Utilities->CallLogPop(1497);
2996  return false;
2997  }
2998  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
2999  {
3000  VecFile >> TempInt;
3001  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3002  {
3003  Utilities->CallLogPop(1499);
3004  return false;
3005  }
3006  VecFile >> TempInt;
3007  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3008  {
3009  Utilities->CallLogPop(1500);
3010  return false;
3011  }
3012  }
3013  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3014  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3015  {
3016  VecFile >> TempInt;
3017  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3018  {
3019  Utilities->CallLogPop(1502);
3020  return false;
3021  }
3022  }
3023  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3024  {
3025  VecFile >> TempInt;
3026  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3027  {
3028  Utilities->CallLogPop(1155);
3029  return false;
3030  }
3031  }
3032  VecFile >> TempInt;
3033  if((TempInt < -1) || (TempInt > 999999)) // Length01
3034  {
3035  Utilities->CallLogPop(1503);
3036  return false;
3037  }
3038  VecFile >> TempInt;
3039  if((TempInt < -1) || (TempInt > 999999)) // Length23
3040  {
3041  Utilities->CallLogPop(1504);
3042  return false;
3043  }
3044  VecFile >> TempInt;
3045  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3046  {
3047  Utilities->CallLogPop(1505);
3048  return false;
3049  }
3050  VecFile >> TempInt;
3051  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3052  {
3053  Utilities->CallLogPop(1506);
3054  return false;
3055  }
3056  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3057  {
3058  Utilities->CallLogPop(1142);
3059  return false; // LocationName
3060  }
3061  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3062  {
3063  Utilities->CallLogPop(1143);
3064  return false; // ActiveTrackElementName
3065  }
3066  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3067  {
3068  Utilities->CallLogPop(1787);
3069  return false; // marker
3070  }
3071  }
3072  int NumberOfInactiveElements = 0;
3073 
3074  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3075  if(NumberOfInactiveElements < 0) // No of active elements
3076  {
3077  Utilities->CallLogPop(1493);
3078  return false;
3079  }
3080  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3081  {
3082  Utilities->CallLogPop(1764);
3083  return false; // **Inactive elements** marker
3084  }
3085  for(int x = 0; x < NumberOfInactiveElements; x++)
3086  {
3087  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3088  {
3089  Utilities->CallLogPop(1765);
3090  return false;
3091  }
3092  VecFile >> TempInt;
3093  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3094  {
3095  Utilities->CallLogPop(1494);
3096  return false;
3097  }
3098  VecFile >> TempInt;
3099  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3100  {
3101  Utilities->CallLogPop(1496);
3102  return false;
3103  }
3104  VecFile >> TempInt;
3105  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3106  {
3107  Utilities->CallLogPop(1498);
3108  return false;
3109  }
3110  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3111  {
3112  Utilities->CallLogPop(1144);
3113  return false; // LocationName
3114  }
3115  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3116  {
3117  Utilities->CallLogPop(1788);
3118  return false; // marker
3119  }
3120  }
3121  Utilities->CallLogPop(1507);
3122  return true;
3123 }
3124 
3125 // ---------------------------------------------------------------------------
3126 
3127 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3128 {
3129  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3130  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3131 
3132  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3133  {
3134  Utilities->CallLogPop(2168);
3135  return false;
3136  }
3137  // filename in Graphics folder, then HPos, then VPos
3138  AnsiString FileName = "", TempStr = "";
3139 
3140  for(int x = 0; x < NumberOfGraphics; x++)
3141  {
3142  TPicture *TempPicture = new TPicture;
3143  try
3144  {
3145  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3146  {
3147  Utilities->CallLogPop(2169);
3148  delete TempPicture;
3149  return false;
3150  }
3151  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3152  delete TempPicture;
3153  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3154  {
3155  Utilities->CallLogPop(2170);
3156  return false;
3157  }
3158  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3159  {
3160  Utilities->CallLogPop(2171);
3161  return false;
3162  }
3163  }
3164  catch(const EInvalidGraphic &e)
3165  {
3166  //move file pointer to end of graphic section for later checks in session files
3167  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3168  Utilities->CheckAndReadFileString(VecFile, TempStr);//VPos
3169  for(int y = x + 1; y < NumberOfGraphics; y++)
3170  {
3171  Utilities->CheckAndReadFileString(VecFile, TempStr);//next FileName
3172  Utilities->CheckAndReadFileString(VecFile, TempStr);//next VPos
3173  Utilities->CheckAndReadFileString(VecFile, TempStr);//next VPos
3174  }
3175  ShowMessage(FileName +
3176  " has an incorrect file format, user graphics can't be loaded. Ensure that all user graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3177  Utilities->CallLogPop(2172);
3178  delete TempPicture;
3179  return true; //for these file errors allow railway or session to be loaded, changed at v2.6.0
3180  }
3181  catch(const Exception &e)
3182  {
3183  //move file pointer to end of graphic section for later checks in session files
3184  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3185  Utilities->CheckAndReadFileString(VecFile, TempStr);//VPos
3186  for(int y = x + 1; y < NumberOfGraphics; y++)
3187  {
3188  Utilities->CheckAndReadFileString(VecFile, TempStr);//next FileName
3189  Utilities->CheckAndReadFileString(VecFile, TempStr);//next VPos
3190  Utilities->CheckAndReadFileString(VecFile, TempStr);//next VPos
3191  }
3192  ShowMessage("Unable to load user graphic files, ensure that " + FileName +
3193  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3194  Utilities->CallLogPop(2173);
3195  delete TempPicture;
3196  return true; //for these file errors allow railway or session to be loaded, changed at v2.6.0
3197  }
3198  }
3199  Utilities->CallLogPop(2174);
3200  return true;
3201 }
3202 
3203 // ---------------------------------------------------------------------------
3204 
3205 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3206 {
3207  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3208  int VecSize = Track->BarriersDownVector.size();
3209 
3210  Utilities->SaveFileInt(OutFile, VecSize);
3211  for(int x = 0; x < VecSize; x++)
3212  {
3214  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3215  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3216  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3217  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3218  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3219  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3220  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3221  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3222  }
3223  Utilities->CallLogPop(1963);
3224 }
3225 
3226 // ---------------------------------------------------------------------------
3227 
3228 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile) //used only in errorfile
3229 {
3230  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3231  int VecSize = Track->ChangingLCVector.size();
3232 
3233  Utilities->SaveFileInt(OutFile, VecSize);
3234  for(int x = 0; x < VecSize; x++)
3235  {
3237  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3238  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3239  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3240  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3241  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3242  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3243  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3244  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3245  }
3246  Utilities->CallLogPop(1980);
3247 }
3248 
3249 // ---------------------------------------------------------------------------
3250 
3251 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3252 {
3253  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3254  int VecSize = Utilities->LoadFileInt(VecFile);
3255 
3256  for(int x = 0; x < VecSize; x++)
3257  {
3258  if(!Utilities->CheckFileInt(VecFile, 0, 2)) //changed from bool at v2.6.0 to allow TypeOfRoute == 2 for barriers manually lowered
3259  {
3260  Utilities->CallLogPop(1970);
3261  return false;
3262  }
3263  if(!Utilities->CheckFileBool(VecFile))
3264  {
3265  Utilities->CallLogPop(1971);
3266  return false;
3267  }
3268  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3269  {
3270  Utilities->CallLogPop(1972);
3271  return false;
3272  }
3273  if(!Utilities->CheckFileDouble(VecFile))
3274  {
3275  Utilities->CallLogPop(1973);
3276  return false;
3277  }
3278  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3279  {
3280  Utilities->CallLogPop(1974);
3281  return false;
3282  }
3283  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3284  {
3285  Utilities->CallLogPop(1975);
3286  return false;
3287  }
3288  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3289  {
3290  Utilities->CallLogPop(1976);
3291  return false;
3292  }
3293  if(!Utilities->CheckFileDouble(VecFile))
3294  {
3295  Utilities->CallLogPop(1977);
3296  return false;
3297  }
3298  }
3299  Utilities->CallLogPop(1978);
3300  return true;
3301 }
3302 
3303 // ---------------------------------------------------------------------------
3304 
3305 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3306 {
3307  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3308  int VecSize = Utilities->LoadFileInt(VecFile);
3309 
3310  for(int x = 0; x < VecSize; x++)
3311  {
3312  TActiveLevelCrossing TALC;
3313  TALC.TypeOfRoute = Utilities->LoadFileInt(VecFile); //changed to int from bool in v2.6.0
3314  TALC.ReducedTimePenalty = Utilities->LoadFileBool(VecFile);
3315  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3316  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3317  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3318  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3319  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3320  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3321  BarriersDownVector.push_back(TALC);
3322  }
3323  Utilities->CallLogPop(1979);
3324 }
3325 
3326 // ---------------------------------------------------------------------------
3327 
3328 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3329 /*
3330  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3331  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3332  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3333 */
3334 {
3335  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3336  TTrackElement Next;
3337 
3338 // Disp->ClearDisplay();
3340  while(ReturnNextInactiveTrackElement(0, Next))
3341  {
3342  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3343  {
3344  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3345  {
3346  // only plot if on screen, to save time
3347  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3349  {
3350  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3351  }
3352  }
3353  }
3354  }
3355 
3356  TextHandler->RebuildFromTextVector(1, Disp); // plot text after inactives so can have text on stations etc
3357 
3358  NextTrackElementPtr = TrackVector.begin();
3359  while(ReturnNextTrackElement(0, Next))
3360  {
3361  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3362  {
3363  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3365  {
3366  if(Next.TrackType == Points)
3367  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3368  else if(Next.TrackType == SignalPost)
3369  PlotSignal(9, Next, Disp);
3370  else if(Next.TrackType == GapJump)
3371  PlotGap(0, Next, Disp);
3372  else
3373  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3374  }
3375  }
3376  }
3377 
3378  if(BothPointFilletsAndBasicLCs)
3379  {
3381  while(ReturnNextInactiveTrackElement(4, Next))
3382  {
3383  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3384  {
3385  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3386  {
3387  // only plot if on screen, to save time, & OK as plotting one by one here
3388  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3390  {
3391  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3392  {
3393  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3394  }
3395  else
3396  {
3397  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3398  }
3399  }
3400  }
3401  }
3402  }
3403  }
3404  Disp->Update();
3405  Utilities->CallLogPop(468);
3406 }
3407 
3408 // ---------------------------------------------------------------------------
3409 
3410 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3411 {
3412  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3413  if(UserGraphicVector.empty())
3414  {
3415  Utilities->CallLogPop(2175);
3416  return;
3417  }
3418  TUserGraphicItem UGI;
3419 
3420  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3421  {
3422  UGI = UserGraphicVectorAt(4, x);
3423  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3424  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3425  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3426  {
3427  Disp->PlotAndAddUserGraphic(0, UGI);
3428  }
3429  }
3430  Disp->Update();
3431  Utilities->CallLogPop(2176);
3432 }
3433 
3434 // ---------------------------------------------------------------------------
3435 
3436 void TTrack::WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
3437 /*
3438  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3439 */
3440 {
3441  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackToImage");
3442 // need to change graphics back to black on white if have a dark background
3443  TColor OldTransparentColour = Utilities->clTransparent;
3444 
3446  {
3447  Utilities->clTransparent = TColor(0xFFFFFF); // white
3450  }
3451  TTrackElement Next;
3452 
3453  Bitmap->Canvas->CopyMode = cmSrcCopy;
3455  Graphics::TBitmap *GraphicOutput;
3456 
3457  while(ReturnNextInactiveTrackElement(2, Next))
3458  {
3459  GraphicOutput = Next.GraphicPtr;
3460  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3461  {
3462  if(Next.LocationName == "") // plot as named or unnamed (striped)
3463  { // default is not striped
3464  switch(Next.SpeedTag)
3465  {
3466  case 76: // t platform
3467  GraphicOutput = RailGraphics->gl76Striped;
3468  break;
3469 
3470  case 77: // h platform
3471  GraphicOutput = RailGraphics->bm77Striped;
3472  break;
3473 
3474  case 78: // v platform
3475  GraphicOutput = RailGraphics->bm78Striped;
3476  break;
3477 
3478  case 79: // r platform
3479  GraphicOutput = RailGraphics->gl79Striped;
3480  break;
3481 
3482  case 96: // concourse
3483  GraphicOutput = RailGraphics->ConcourseStriped;
3484  break;
3485 
3486  case 129: // v footbridge
3487  GraphicOutput = RailGraphics->gl129Striped;
3488  break;
3489 
3490  case 130: // h footbridge
3491  GraphicOutput = RailGraphics->gl130Striped;
3492  break;
3493 
3494  case 131: // non-station named loc
3495  GraphicOutput = RailGraphics->bmNameStriped;
3496  break;
3497 
3498  case 145: // v underpass
3499  GraphicOutput = RailGraphics->gl145Striped;
3500  break;
3501 
3502  case 146: // h underpass
3503  GraphicOutput = RailGraphics->gl146Striped;
3504  break;
3505 
3506  default:
3507  GraphicOutput = Next.GraphicPtr;
3508  break;
3509  }
3510  }
3511  if(Next.SpeedTag == 144) // level crossing
3512  {
3513  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
3514  {
3515  GraphicOutput = RailGraphics->LCBothVer;
3516  }
3517  else
3518  {
3519  GraphicOutput = RailGraphics->LCBothHor;
3520  }
3521  }
3522  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3523  }
3524  }
3525 
3526  NextTrackElementPtr = TrackVector.begin();
3527  while(ReturnNextTrackElement(2, Next))
3528  {
3529  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3530  {
3531  if(Next.TrackType == Points) // plot both fillets
3532  {
3533  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3534  if(Next.SpeedTag < 28)
3535  {
3536  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3538  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3540  }
3541  else if(Next.SpeedTag < 132)
3542  {
3543  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3544  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
3545  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3546  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
3547  }
3548  else
3549  {
3550  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3551  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
3552  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3553  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
3554  }
3555  }
3556  else if(Next.TrackType == GapJump) // plot as connected or unconnected
3557  {
3558  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
3559  {
3560  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
3561  }
3562  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
3563  {
3564  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
3565  }
3566  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
3567  {
3568  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
3569  }
3570  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
3571  {
3572  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
3573  }
3574  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
3575  {
3576  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
3577  }
3578  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
3579  {
3580  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
3581  }
3582  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
3583  {
3584  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
3585  }
3586  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
3587  {
3588  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
3589  }
3590  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
3591  {
3592  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
3593  }
3594  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
3595  {
3596  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
3597  }
3598  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
3599  {
3600  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
3601  }
3602  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
3603  {
3604  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
3605  }
3606  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
3607  {
3608  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
3609  }
3610  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
3611  {
3612  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
3613  }
3614  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
3615  {
3616  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
3617  }
3618  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
3619  {
3620  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
3621  }
3622  }
3623  // below added for version 0.6, only stop signals to be drawn
3624  else if(Next.TrackType == SignalPost)
3625  {
3626  for(int x = 0; x < 40; x++)
3627  {
3628  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
3629  {
3630  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
3631  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
3632  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
3633  int HOffset = 0;
3634  if(Next.SpeedTag > 73)
3635  HOffset = 5;
3636  else if(Next.SpeedTag == 71)
3637  HOffset = 9;
3638  int VOffset = 0;
3639  if(Next.SpeedTag == 69)
3640  VOffset = 9;
3641  else if(Next.SpeedTag == 72)
3642  VOffset = 5;
3643  else if(Next.SpeedTag == 74)
3644  VOffset = 5;
3645  Graphics::TBitmap *GraphicPtr;
3646  if(Next.SpeedTag > 71)
3647  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
3648  else if(Next.SpeedTag < 70)
3649  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
3650  else
3651  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
3652  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
3653  // plot special signal platform if present
3654  Graphics::TBitmap* SignalPlatformGraphic;
3655  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
3656  {
3657  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
3658  }
3659  // now plot signal (double yellow overwrites most of signal platform if present)
3660  // below amended for version 0.6
3662  {
3663  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
3664  }
3665  else if(Next.SigAspect == TTrackElement::TwoAspect)
3666  {
3667  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
3668  }
3669  else if(Next.SigAspect == TTrackElement::GroundSignal)
3670  {
3671  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
3672  }
3673  else // 4 aspect
3674  {
3675  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
3676  }
3677  break;
3678  }
3679  }
3680  }
3681  else
3682  {
3683  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3684  }
3685  }
3686  }
3687  if(OldTransparentColour != clB5G5R5)
3688  {
3689  Utilities->clTransparent = OldTransparentColour; // restore
3692  }
3693  Utilities->CallLogPop(1533);
3694 }
3695 
3696 // ---------------------------------------------------------------------------
3697 
3698 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
3699 {
3700  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
3701  if(UserGraphicVector.empty())
3702  {
3703  Utilities->CallLogPop(2192);
3704  return;
3705  }
3706  else
3707  {
3708  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3709  {
3710  Bitmap->Canvas->CopyMode = cmSrcCopy;
3711  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
3712  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
3713  }
3714  }
3715  Utilities->CallLogPop(2193);
3716 }
3717 
3718 // ---------------------------------------------------------------------------
3719 
3720 void TTrack::WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
3721 /*
3722  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3723  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
3724 */
3725 {
3726  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackToImage");
3727 // need to change graphics back to black on white if have a dark background
3728  TColor OldTransparentColour = Utilities->clTransparent;
3729 
3731  {
3732  Utilities->clTransparent = TColor(0xFFFFFF); // white
3735  }
3736  TTrackElement Next;
3737 
3738  Bitmap->Canvas->CopyMode = cmSrcCopy;
3740  Graphics::TBitmap *GraphicOutput;
3741 
3742  while(ReturnNextInactiveTrackElement(3, Next))
3743  {
3744  GraphicOutput = Next.GraphicPtr; // no striped name graphics
3745  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3746  {
3747  if(Next.SpeedTag == 144) // level crossing
3748  {
3749  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
3750  if(BaseElement == 1) // hor element
3751  {
3752  if(Next.Attribute == 1) // open to trains
3753  {
3754  GraphicOutput = RailGraphics->LCBothHor;
3755  }
3756  else // plot as closed to trains if in any other state
3757  {
3758  GraphicOutput = RailGraphics->LCBothVer;
3759  }
3760  }
3761  else // vert element
3762  {
3763  if(Next.Attribute == 1) // open to trains
3764  {
3765  GraphicOutput = RailGraphics->LCBothVer;
3766  }
3767  else // plot as closed to trains if in any other state
3768  {
3769  GraphicOutput = RailGraphics->LCBothHor;
3770  }
3771  }
3772  }
3773  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3774  }
3775  }
3776 
3777  NextTrackElementPtr = TrackVector.begin();
3778  while(ReturnNextTrackElement(3, Next))
3779  {
3780  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3781  {
3782  if(Next.TrackType == Points) // plot active fillet
3783  {
3784  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3785  if(Next.SpeedTag < 28)
3786  {
3787  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3789  }
3790  else if(Next.SpeedTag < 132)
3791  {
3792  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3794  }
3795  else
3796  {
3797  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3799  }
3800  }
3801  else if(Next.TrackType == GapJump) // plot as connected
3802  {
3803  if(Next.SpeedTag == 88)
3804  {
3805  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
3806  }
3807  else if(Next.SpeedTag == 89)
3808  {
3809  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
3810  }
3811  else if(Next.SpeedTag == 90)
3812  {
3813  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
3814  }
3815  else if(Next.SpeedTag == 91)
3816  {
3817  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
3818  }
3819  else if(Next.SpeedTag == 92)
3820  {
3821  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
3822  }
3823  else if(Next.SpeedTag == 93)
3824  {
3825  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
3826  }
3827  else if(Next.SpeedTag == 94)
3828  {
3829  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
3830  }
3831  else if(Next.SpeedTag == 95)
3832  {
3833  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
3834  }
3835  }
3836  else if(Next.TrackType == SignalPost) // plot in correct colour
3837  {
3838  for(int x = 0; x < 40; x++)
3839  {
3840  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
3841  {
3842  // plot blank first, then plot platform if present - (always not striped for operating railway)
3843  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
3844  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
3845  int HOffset = 0;
3846  if(Next.SpeedTag > 73)
3847  HOffset = 5;
3848  else if(Next.SpeedTag == 71)
3849  HOffset = 9;
3850  int VOffset = 0;
3851  if(Next.SpeedTag == 69)
3852  VOffset = 9;
3853  else if(Next.SpeedTag == 72)
3854  VOffset = 5;
3855  else if(Next.SpeedTag == 74)
3856  VOffset = 5;
3857  Graphics::TBitmap *GraphicPtr;
3858  if(Next.SpeedTag > 71)
3859  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
3860  else if(Next.SpeedTag < 70)
3861  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
3862  else
3863  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
3864  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
3865  // plot special signal platform if present
3866  Graphics::TBitmap* SignalPlatformGraphic;
3867  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
3868  {
3869  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
3870  }
3871  // now plot signal (double yellow overwrites most of signal platform if present)
3872  // below amended for version 0.6
3874  {
3875  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
3876  }
3877  else if(Next.SigAspect == TTrackElement::TwoAspect)
3878  {
3879  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
3880  }
3881  else if(Next.SigAspect == TTrackElement::GroundSignal)
3882  {
3883  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
3884  }
3885  else // 4 aspect
3886  {
3887  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
3888  }
3889  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
3890  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
3891  {
3892  if(Next.SpeedTag == 68)
3893  {
3894  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
3895  }
3896  if(Next.SpeedTag == 69)
3897  {
3898  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
3899  }
3900  if(Next.SpeedTag == 70)
3901  {
3902  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
3903  }
3904  if(Next.SpeedTag == 71)
3905  {
3906  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
3907  }
3908  if(Next.SpeedTag == 72)
3909  {
3910  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
3911  }
3912  if(Next.SpeedTag == 73)
3913  {
3914  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
3915  }
3916  if(Next.SpeedTag == 74)
3917  {
3918  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
3919  }
3920  if(Next.SpeedTag == 75)
3921  {
3922  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
3923  }
3924  }
3925  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
3926  {
3927  for(int x = 0; x < 40; x++)
3928  {
3929  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
3930  {
3931  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
3932  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
3933  Utilities->RHSignalFlag); // in case existing signal is a double yellow
3934  // plot special signal platform if present
3935  Graphics::TBitmap* SignalPlatformGraphic;
3936  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
3937  {
3938  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
3939  }
3940  // now plot signal
3941  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
3942  break;
3943  }
3944  }
3945  }
3946  break;
3947  }
3948  }
3949  }
3950  else
3951  {
3952  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3953  }
3954  }
3955  }
3956  if(OldTransparentColour != clB5G5R5)
3957  {
3958  Utilities->clTransparent = OldTransparentColour; // restore
3961  }
3962  Utilities->CallLogPop(1701);
3963 }
3964 
3965 // ---------------------------------------------------------------------------
3966 
3967 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
3968 {
3969  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
3970  for(unsigned int x = 0; x < TrackVector.size(); x++)
3971  {
3972  if(TrackVector.at(x).TrackType == GapJump)
3973  {
3974  if(TrackVector.at(x).Conn[0] > -1)
3975  continue; // to next 'x' value as this element has already been set
3976  // here if identify a GapJump element not yet set
3977  GapPos = x;
3978  GapHLoc = TrackVector.at(x).HLoc;
3979  GapVLoc = TrackVector.at(x).VLoc;
3980  // highlight it
3982  Utilities->CallLogPop(469);
3983  return true;
3984  }
3985  }
3986  Utilities->CallLogPop(470);
3987  return false;
3988 }
3989 
3990 // ---------------------------------------------------------------------------
3991 
3992 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
3993 {
3994  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
3995  AnsiString(VLoc));
3996  int Position;
3997  TTrackElement TrackElement;
3998 
3999  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
4000  {
4001  Utilities->CallLogPop(471);
4002  return false; // not found
4003  }
4004  if(TrackElement.TrackType != GapJump)
4005  {
4006  Utilities->CallLogPop(472);
4007  return false; // found something but not a gap
4008  }
4009  if(Position == GapPos)
4010  {
4011  Utilities->CallLogPop(473);
4012  return false; // selected original gap
4013  }
4014  if(TrackVector.at(Position).Conn[0] != -1)
4015  {
4016  Utilities->CallLogPop(474);
4017  return false; // already selected
4018  }
4019  TrackVector.at(Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4020  TrackVector.at(Position).ConnLinkPos[0] = 0;
4021  TrackVector.at(GapPos).Conn[0] = Position; // set other one similarly
4022  TrackVector.at(GapPos).ConnLinkPos[0] = 0;
4023 // now highlight the selected location
4024  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4025  Utilities->CallLogPop(475);
4026  return true;
4027 }
4028 
4029 // ---------------------------------------------------------------------------
4030 
4031 bool TTrack::GapsUnset(int Caller)
4032  // returns true if there are gaps and any are unset
4033 {
4034  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4035  if(TrackVector.size() == 0)
4036  {
4037  Utilities->CallLogPop(476);
4038  return false;
4039  }
4040  for(unsigned int x = 0; x < TrackVector.size(); x++)
4041  {
4042  if(TrackVector.at(x).TrackType == GapJump)
4043  {
4044  if(TrackVector.at(x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4045  {
4046  Utilities->CallLogPop(477);
4047  return true;
4048  }
4049  else // set, but may not have matching element, or that element may not be set
4050  {
4051  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
4052  // check that the element pointed to by the gap link is a GapJump
4053  {
4054  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4055  Utilities->CallLogPop(1137);
4056  return false;
4057  }
4058 // here if gap connection is itself a GapJump
4059  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
4060  // check that the element pointed to by the gap link is a GapJump & that its gap link
4061  // points back to 'x'
4062  {
4063  Utilities->CallLogPop(478);
4064  return true;
4065  }
4066 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4067  }
4068  } // if(TrackVector.at(x).TrackType == GapJump)
4069  } // for x...
4070  Utilities->CallLogPop(479);
4071  return false;
4072 }
4073 
4074 // ---------------------------------------------------------------------------
4075 
4076 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4077 {
4078  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4079  for(unsigned int x = 0; x < TrackVector.size(); x++)
4080  {
4081  if(TrackVector.at(x).TrackType == GapJump)
4082  {
4083  Utilities->CallLogPop(1105);
4084  return false;
4085  }
4086  }
4087  Utilities->CallLogPop(1106);
4088  return true;
4089 }
4090 
4091 // ---------------------------------------------------------------------------
4092 
4093 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4094 {
4095  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4096  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4097  {
4098  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
4099  {
4100  Utilities->CallLogPop(1107);
4101  return false;
4102  }
4103  }
4104  for(unsigned int x = 0; x < TrackVector.size(); x++)
4105  {
4106  if(TrackVector.at(x).FixedNamedLocationElement)
4107  {
4108  Utilities->CallLogPop(1108);
4109  return false;
4110  }
4111  }
4112  Utilities->CallLogPop(1109);
4113  return true;
4114 }
4115 
4116 // ---------------------------------------------------------------------------
4117 
4119  // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4120  // returns false otherwise or if there are no NamedLocationElements
4121 {
4122  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4123  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4124  {
4125  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
4126  {
4127  if(InactiveTrackVector.at(x).LocationName == "")
4128  {
4129  Utilities->CallLogPop(1110);
4130  return true;
4131  }
4132  }
4133  }
4134  for(unsigned int x = 0; x < TrackVector.size(); x++)
4135  {
4136  if(TrackVector.at(x).FixedNamedLocationElement)
4137  {
4138  if(TrackVector.at(x).LocationName == "")
4139  {
4140  Utilities->CallLogPop(1111);
4141  return true;
4142  }
4143  }
4144  }
4145  Utilities->CallLogPop(1112);
4146  return false;
4147 }
4148 
4149 // ---------------------------------------------------------------------------
4150 
4151 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4152 {
4153  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4154  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4155  Utilities->CallLogPop(480);
4156 }
4157 
4158 // ---------------------------------------------------------------------------
4159 
4161 {
4162  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4163  if(TrackVector.size() == 0)
4164  {
4165  Utilities->CallLogPop(481);
4166  return;
4167  }
4168  for(unsigned int x = 0; x < TrackVector.size(); x++)
4169  {
4170  if(TrackVector.at(x).TrackType == GapJump)
4171  {
4172  if(TrackVector.at(x).Conn[0] > -1) // set
4173  {
4174  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
4175  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4176  {
4177  TrackVector.at(x).Conn[0] = -1;
4178  TrackVector.at(x).ConnLinkPos[0] = -1;
4179  continue; // to next 'x'
4180  }
4181 // here if gap connection is itself a GapJump
4182  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
4183  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4184  // if not clear Conns & CLks
4185  {
4186  TrackVector.at(x).Conn[0] = -1;
4187  TrackVector.at(x).ConnLinkPos[0] = -1;
4188  continue; // to next 'x'
4189  }
4190 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4191 // hence no more action needed on these Conns & CLks
4192  }
4193  } // else //gap jump
4194  } // for x...
4195 // throw Exception("Test Exception");//test
4196  Utilities->CallLogPop(482);
4197 }
4198 
4199 // ---------------------------------------------------------------------------
4200 
4201 void TTrack::ResetSignals(int Caller)
4202 {
4203  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4204  for(unsigned int x = 0; x < TrackVector.size(); x++)
4205  {
4206  if(TrackVector.at(x).TrackType == SignalPost)
4207  {
4208  TrackVector.at(x).Attribute = 0;
4209  }
4210  }
4211  Utilities->CallLogPop(483);
4212 }
4213 
4214 // ---------------------------------------------------------------------------
4215 
4216 void TTrack::ResetPoints(int Caller)
4217 {
4218  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4219  for(unsigned int x = 0; x < TrackVector.size(); x++)
4220  {
4221  if(TrackVector.at(x).TrackType == Points)
4222  {
4223  TrackVector.at(x).Attribute = 0;
4224  }
4225  }
4226  Utilities->CallLogPop(484);
4227 }
4228 
4229 // ---------------------------------------------------------------------------
4230 
4231 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4232 {
4233  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4234  if(TrackVector.empty())
4235  {
4236  TrackMap.clear();
4237  Utilities->CallLogPop(485);
4238  return true;
4239  }
4240 
4241 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4242  THVPair TrackMapKeyPair;
4243 
4244  NewVector.clear();
4245  TTrackMapIterator TrackMapPtr;
4246 
4247  if(!TrackMap.empty())
4248  {
4249  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4250  {
4251  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4252  }
4253  }
4254  if(NewVector.size() != TrackMap.size())
4255  {
4256  throw Exception("Error - Map & Vector different sizes");
4257  }
4258  unsigned int NonZeroCount = 0;
4259 
4260  for(unsigned int x = 0; x < TrackVector.size(); x++)
4261  {
4262  if(TrackVector.at(x).TrackType != Erase)
4263  NonZeroCount++;
4264  }
4265  if(NewVector.size() != NonZeroCount)
4266  {
4267  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4268  }
4269 
4271  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4272  TTrackMapEntry TrackMapEntry;
4273 
4274  for(unsigned int x = 0; x < TrackVector.size(); x++)
4275  {
4276  TrackMapKeyPair.first = TrackVector.at(x).HLoc;
4277  TrackMapKeyPair.second = TrackVector.at(x).VLoc;
4278  TrackMapEntry.first = TrackMapKeyPair;
4279  TrackMapEntry.second = x;
4280  if(!(TrackMap.insert(TrackMapEntry).second))
4281  {
4282  throw Exception("Error - map insertion failure, TrackVector in error");
4283  }
4284  }
4285 // All track now relocated in TrackVector, reset all Conns & CLks
4286  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4287  {
4288  for(unsigned int y = 0; y < 4; y++)
4289  {
4290  TrackVector.at(x).Conn[y] = -1;
4291  TrackVector.at(x).ConnLinkPos[y] = -1;
4292  }
4293  }
4294  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4295  CheckMapAndTrack(4); // test
4296  CheckMapAndInactiveTrack(4); // test
4297  CheckLocationNameMultiMap(8); // test
4298  if(!ResetGapsFromGapMap(1))
4299  {
4300  Utilities->CallLogPop(489);
4301  return false;
4302  }
4303  Utilities->CallLogPop(490);
4304  return true;
4305 }
4306 
4307 // ---------------------------------------------------------------------------
4308 
4309 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4310 {
4311  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4312  GapMap.clear();
4313  THVPair GapMapKeyPair, GapMapValuePair;
4314  TGapMapEntry GapMapEntry;
4315 
4316  for(unsigned int x = 0; x < TrackVector.size(); x++)
4317  {
4318  if(TrackVector.at(x).TrackType == GapJump)
4319  {
4320  GapMapKeyPair.first = TrackVector.at(x).HLoc;
4321  GapMapKeyPair.second = TrackVector.at(x).VLoc;
4322  GapMapEntry.first = GapMapKeyPair;
4323  if(TrackVector.at(x).Conn[0] == -1)
4324  {
4325  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4326  }
4327  GapMapValuePair.first = TrackElementAt(7, TrackVector.at(x).Conn[0]).HLoc;
4328  GapMapValuePair.second = TrackElementAt(8, TrackVector.at(x).Conn[0]).VLoc;
4329  GapMapEntry.second = GapMapValuePair;
4330  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4331  {
4332  GapMap.insert(GapMapEntry);
4333  }
4334  }
4335  }
4336  Utilities->CallLogPop(492);
4337 }
4338 
4339 // ---------------------------------------------------------------------------
4340 
4341 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4342 {
4343  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4344  LocError = false;
4345  bool CheckForLinks = false;
4346 
4347  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4348  {
4349  if(TrackVector.at(x).TrackType == Erase) //Erase isn't used any more as a track type
4350  continue; // skip blank elements
4351 // check footcrossing linkages
4352  if(TrackVector.at(x).TrackType == FootCrossing)
4353  {
4354  if(!CheckFootCrossingLinks(1, TrackVector.at(x)))
4355  {
4356  ShowMessage(
4357  "Footbridge or underpass connection error. Each end must connect to a platform, concourse or other footbridge or underpass, and they can't connect to each other");
4358  HLoc = TrackVector.at(x).HLoc;
4359  VLoc = TrackVector.at(x).VLoc;
4360  LocError = true;
4361  Utilities->CallLogPop(493);
4362  return false;
4363  }
4364  }
4365  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4366  {
4367  CheckForLinks = false;
4368  if(TrackVector.at(x).Link[y] <= 0)
4369  continue; // no link
4370  if((TrackVector.at(x).TrackType == Buffers) && (TrackVector.at(x).Config[y] == End))
4371  continue; // buffer
4372  if(TrackVector.at(x).Config[y] == Gap)
4373  continue; // gaps set later from GapMap
4374 
4375  // get required H & V for track element joining link 'y'
4376  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
4377  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
4378  // find track element if present
4379  bool ConnectionFoundFlag;
4380  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
4381  if((TrackVector.at(x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4382  {
4383  ShowMessage("Can't have a track element adjacent to a continuation exit");
4384  HLoc = TrackVector.at(x).HLoc;
4385  VLoc = TrackVector.at(x).VLoc;
4386  LocError = true;
4387  if(FinalCall)
4388  {
4389  throw Exception("Error in final track linkage - continuation adjacent to another element");
4390  }
4391  Utilities->CallLogPop(1539);
4392  return false;
4393  }
4394  if((TrackVector.at(x).TrackType == Continuation) && (TrackVector.at(x).Config[y] == End))
4395  continue;
4396  if(ConnectionFoundFlag)
4397  {
4398  TrackVector.at(x).Conn[y] = VecPos;
4399  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
4400  bool LinkFoundFlag = false;
4401  if((TrackVector.at(x).Config[1 - y] == Signal) && IsLCAtHV(50, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
4402  { // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
4403  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
4404  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
4405  }
4406  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover))
4407  && (TrackVector.at(VecPos).TrackType == Buffers))
4408  {
4409  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
4410  // need room for a train (2 elements) without fouling points or signals
4411  }
4412  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover) ||
4413  (TrackVector.at(x).TrackType == Bridge)) && (TrackVector.at(VecPos).TrackType == Continuation))
4414  {
4415  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
4416  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
4417  // if continuation next to a signal; also none of these can be a named location, and a continuation can
4418  // be named but needs the adjacent element named too
4419  }
4420  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
4421  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
4422  {
4423  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
4424  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4425  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4426  }
4427  else if((TrackVector.at(x).Config[y] == Signal) && (TrackVector.at(VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage)
4428  {
4429  ShowMessage("Signal facing a bridge - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
4430  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4431  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4432  }
4433  else if(IsLCAtHV(45, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc) && IsLCAtHV(46, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
4434  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
4435  {
4436  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
4437  }
4438  else
4439  CheckForLinks = true;
4440  if(CheckForLinks)
4441  {
4442  for(unsigned int a = 0; a < 4; a++)
4443  {
4444  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
4445  (TrackVector.at(VecPos).Config[a] != Gap))
4446  {
4447  TrackVector.at(x).ConnLinkPos[y] = a;
4448  // note - this ensures that if the connecting element is a leading point
4449  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4450  // (Points have the same link value for both [0] and [2])
4451  LinkFoundFlag = true;
4452  break; // stop after first find or will find later link for leading point
4453  }
4454  }
4455  }
4456  // if there isn't a corresponding link, or buffer check fails, set the invert values for the offending element
4457  if(!LinkFoundFlag)
4458  {
4459  HLoc = TrackVector.at(x).HLoc;
4460  VLoc = TrackVector.at(x).VLoc;
4461  LocError = true;
4462  if(FinalCall)
4463  {
4464  throw Exception("Error in final track linkage - invalid link");
4465  }
4466  Utilities->CallLogPop(494);
4467  return false;
4468  }
4469  }
4470  // if there isn't a connection set the invert values for the offending element
4471  else // if(ConnectionFoundFlag)
4472  {
4473  HLoc = TrackVector.at(x).HLoc;
4474  VLoc = TrackVector.at(x).VLoc;
4475  LocError = true;
4476  if(FinalCall)
4477  {
4478  throw Exception("Error in final track linkage - connection not found");
4479  }
4480  Utilities->CallLogPop(495);
4481  return false;
4482  }
4483  }
4484  } // for(unsigned int x=0;x<TrackVector.size();x++)
4485 
4486  if(FinalCall)
4488 
4489 // final check
4490  bool ConnErrorFlag = false;
4491 
4492  for(unsigned int x = 0; x < TrackVector.size(); x++)
4493  {
4494  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
4495  ConnErrorFlag = true;
4496  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
4497  ConnErrorFlag = true;
4498  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
4499  ConnErrorFlag = true;
4500  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
4501  ConnErrorFlag = true;
4502  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
4503  {
4504  if(TrackVector.at(x).ActiveTrackElementName == "")
4505  {
4506  if((TrackVector.at(x).StationEntryStopLinkPos1 != -1) || (TrackVector.at(x).StationEntryStopLinkPos2 != -1))
4507  {
4508  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
4509  }
4510  }
4511  }
4512  }
4513  if(ConnErrorFlag)
4514  {
4515  if(FinalCall)
4516  {
4517  throw Exception("ConnError in LinkTrack - Final");
4518  }
4519  else
4520  {
4521  throw Exception("ConnError in LinkTrack - Precheck");
4522  }
4523  }
4524 
4525  bool CLkErrorFlag = false;
4526 
4527  for(unsigned int x = 0; x < TrackVector.size(); x++)
4528  {
4529  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
4530  CLkErrorFlag = true;
4531  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
4532  CLkErrorFlag = true;
4533  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
4534  CLkErrorFlag = true;
4535  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
4536  CLkErrorFlag = true;
4537  }
4538 
4539  if(CLkErrorFlag)
4540  {
4541  if(FinalCall)
4542  {
4543  throw Exception("CLkError in LinkTrack - Final");
4544  }
4545  else
4546  {
4547  throw Exception("CLkError in LinkTrack - Precheck");
4548  }
4549  }
4550 
4551 // set element lengths to min of 20m
4552  for(unsigned int x = 0; x < TrackVector.size(); x++)
4553  {
4554  if(TrackVector.at(x).TrackType == Erase)
4555  continue; // skip blank elements
4556  if(TrackVector.at(x).Length01 < 20)
4557  TrackVector.at(x).Length01 = 20;
4558  if((TrackVector.at(x).Length23 < 20) && (TrackVector.at(x).Length23 != -1))
4559  TrackVector.at(x).Length23 = 20;
4560  }
4561 
4562  if(FinalCall) // ONLY at FinalCall, no point calling twice
4563  {
4564  CalcHLocMinEtc(3);
4565  }
4566  Utilities->CallLogPop(497);
4567  return true;
4568 }
4569 
4570 // ---------------------------------------------------------------------------
4571 
4572 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
4573 {
4574  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
4575  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4576  {
4577  if(TrackVector.at(x).TrackType == Erase)
4578  continue; // skip blank elements
4579 
4580 // check footcrossing linkages
4581  if(TrackVector.at(x).TrackType == FootCrossing)
4582  {
4583  if(!CheckFootCrossingLinks(3, TrackVector.at(x)))
4584  {
4585  Utilities->CallLogPop(1127);
4586  return false;
4587  }
4588  }
4589 
4590  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4591  {
4592  if(TrackVector.at(x).Link[y] <= 0)
4593  continue; // no link
4594  if((TrackVector.at(x).TrackType == Buffers) && (TrackVector.at(x).Config[y] == End))
4595  continue; // buffer
4596  if(TrackVector.at(x).Config[y] == Gap)
4597  continue; // gaps set later from GapMap
4598 
4599  // get required H & V for track element joining link 'y'
4600  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
4601  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
4602  // find track element if present
4603  bool ConnectionFoundFlag;
4604  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
4605  if((TrackVector.at(x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4606  {
4607  if(FinalCall)
4608  {
4609  throw Exception("Error in final track linkage - continuation adjacent to another element");
4610  }
4611  Utilities->CallLogPop(1540);
4612  return false;
4613  }
4614  if((TrackVector.at(x).TrackType == Continuation) && (TrackVector.at(x).Config[y] == End))
4615  continue;
4616  if(ConnectionFoundFlag)
4617  {
4618  TrackVector.at(x).Conn[y] = VecPos;
4619  bool LinkFoundFlag = false;
4620  // find connecting link in the newly found track element if there is one & make checks
4621  if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover)) &&
4622  (TrackVector.at(VecPos).TrackType == Buffers))
4623  {
4624  Utilities->CallLogPop(1541);
4625  return false;
4626  }
4627  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover) ||
4628  (TrackVector.at(x).TrackType == Bridge)) && (TrackVector.at(VecPos).TrackType == Continuation))
4629  {
4630  Utilities->CallLogPop(1542);
4631  return false;
4632  }
4633  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
4634  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
4635  {
4636  Utilities->CallLogPop(1543);
4637  return false;
4638  }
4639  else if(IsLCAtHV(47, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc) && IsLCAtHV(48, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
4640  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
4641  {
4642  Utilities->CallLogPop(1981);
4643  return false;
4644  }
4645 /* remove this restriction now that not permitted to treat a named continuation as a location stop
4646  else if(TrackVector.at(x).TrackType == Continuation)
4647  {
4648  int H = TrackVector.at(x).HLoc;
4649  int V = TrackVector.at(x).VLoc;
4650  bool FoundFlag = false;
4651  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
4652  if(FoundFlag)
4653  {
4654  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
4655  {
4656  int NewH = TrackElementAt(727, (TrackVector.at(x).Conn[1])).HLoc;
4657  int NewV = TrackElementAt(728, (TrackVector.at(x).Conn[1])).VLoc;
4658  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
4659  if(FoundFlag)
4660  {
4661  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
4662  {
4663  Utilities->CallLogPop(1544);
4664  return false;
4665  }
4666  }
4667  else
4668  {
4669  Utilities->CallLogPop(1545);
4670  return false;
4671  }
4672  }
4673  }
4674  }
4675 */
4676  for(unsigned int a = 0; a < 4; a++)
4677  {
4678  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
4679  (TrackVector.at(VecPos).Config[a] != Gap))
4680  {
4681  TrackVector.at(x).ConnLinkPos[y] = a;
4682  // note - this ensures that if the connecting element is a leading point
4683  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4684  // (Points have the same link value for both [0] and [2])
4685  LinkFoundFlag = true;
4686  break; // stop after first find or will find later link for leading point
4687  }
4688  }
4689  if(!LinkFoundFlag)
4690  {
4691  if(FinalCall)
4692  {
4693  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
4694  }
4695  Utilities->CallLogPop(1128);
4696  return false;
4697  }
4698  }
4699  else // if(ConnectionFoundFlag)
4700  {
4701  if(FinalCall)
4702  {
4703  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
4704  }
4705  Utilities->CallLogPop(1129);
4706  return false;
4707  }
4708  }
4709  } // for(unsigned int x=0;x<TrackVector.size();x++)
4710 
4711  if(FinalCall)
4713 
4714 // final check
4715  bool ConnErrorFlag = false;
4716 
4717  for(unsigned int x = 0; x < TrackVector.size(); x++)
4718  {
4719  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
4720  ConnErrorFlag = true;
4721  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
4722  ConnErrorFlag = true;
4723  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
4724  ConnErrorFlag = true;
4725  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
4726  ConnErrorFlag = true;
4727  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
4728  {
4729  if(TrackVector.at(x).ActiveTrackElementName == "")
4730  {
4731  if((TrackVector.at(x).StationEntryStopLinkPos1 != -1) || (TrackVector.at(x).StationEntryStopLinkPos2 != -1))
4732  {
4733  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
4734  }
4735  }
4736  }
4737  }
4738  if(ConnErrorFlag)
4739  {
4740  if(FinalCall)
4741  {
4742  throw Exception("ConnError in LinkTrack - Final");
4743  }
4744  else
4745  {
4746  throw Exception("ConnError in LinkTrack - Precheck");
4747  }
4748  }
4749 
4750  bool CLkErrorFlag = false;
4751 
4752  for(unsigned int x = 0; x < TrackVector.size(); x++)
4753  {
4754  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
4755  CLkErrorFlag = true;
4756  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
4757  CLkErrorFlag = true;
4758  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
4759  CLkErrorFlag = true;
4760  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
4761  CLkErrorFlag = true;
4762  }
4763 
4764  if(CLkErrorFlag)
4765  {
4766  if(FinalCall)
4767  {
4768  throw Exception("CLkError in LinkTrack - Final");
4769  }
4770  else
4771  {
4772  throw Exception("CLkError in LinkTrack - Precheck");
4773  }
4774  }
4775 
4776 // set element lengths to min of 20m
4777  for(unsigned int x = 0; x < TrackVector.size(); x++)
4778  {
4779  if(TrackVector.at(x).TrackType == Erase)
4780  continue; // skip blank elements
4781  if(TrackVector.at(x).Length01 < 20)
4782  TrackVector.at(x).Length01 = 20;
4783  if((TrackVector.at(x).Length23 < 20) && (TrackVector.at(x).Length23 != -1))
4784  TrackVector.at(x).Length23 = 20;
4785  }
4786 
4787  if(FinalCall) // ONLY at FinalCall, no point calling twice
4788  {
4789  CalcHLocMinEtc(7);
4790  }
4791  Utilities->CallLogPop(1130);
4792  return true;
4793 }
4794 
4795 // ---------------------------------------------------------------------------
4796 
4797 bool TTrack::IsTrackLinked(int Caller) // not used any more
4798 {
4799  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
4800  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4801  {
4802  if(TrackVector.at(x).TrackType == Erase)
4803  {
4804  Utilities->CallLogPop(498);
4805  return false;
4806  }
4807 
4808 // check foot linkages
4809  if(TrackVector.at(x).TrackType == FootCrossing)
4810  {
4811  if(!CheckFootCrossingLinks(2, TrackVector.at(x)))
4812  {
4813  Utilities->CallLogPop(499);
4814  return false;
4815  }
4816  }
4817 
4818  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4819  {
4820  if(TrackVector.at(x).Link[y] <= 0)
4821  continue; // no link
4822  if(TrackVector.at(x).Config[y] == End)
4823  continue; // buffer or continuation
4824  if(TrackVector.at(x).Config[y] == Gap)
4825  continue; // gaps set later from GapMap
4826 
4827  // get required H & V for track element joining link 'y'
4828  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
4829  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
4830  // find track element if present
4831  bool ConnectionFoundFlag = false;
4832  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
4833  if(ConnectionFoundFlag)
4834  {
4835  TrackVector.at(x).Conn[y] = VecPos;
4836  // find connecting link in the newly found track element if there is one & make buffer check
4837  bool LinkFoundFlag = false;
4838  if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover)) &&
4839  (TrackVector.at(VecPos).TrackType == Buffers))
4840  {
4841  Utilities->CallLogPop(500);
4842  return false;
4843  }
4844  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
4845  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
4846  {
4847  Utilities->CallLogPop(501);
4848  return false;
4849  }
4850  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == Continuation))
4851  {
4852  Utilities->CallLogPop(502);
4853  return false;
4854  }
4855  else
4856  {
4857  for(unsigned int a = 0; a < 4; a++)
4858  {
4859  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
4860  (TrackVector.at(VecPos).Config[a] != Gap))
4861  {
4862  TrackVector.at(x).ConnLinkPos[y] = a;
4863  // note - this ensures that if the connecting element is a leading point
4864  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4865  // (Points have the same link value for both [0] and [2])
4866  LinkFoundFlag = true;
4867  break; // stop after first find or will find later link for leading point
4868  }
4869  }
4870  }
4871  if(!LinkFoundFlag)
4872  {
4873  Utilities->CallLogPop(503);
4874  return false;
4875  }
4876  }
4877  else // if(ConnectionFoundFlag)
4878  {
4879  Utilities->CallLogPop(504);
4880  return false;
4881  }
4882  }
4883  } // for(unsigned int x=0;x<TrackVector.size();x++)
4884 
4885 // final check
4886  bool ConnErrorFlag = false;
4887 
4888  for(unsigned int x = 0; x < TrackVector.size(); x++)
4889  {
4890  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
4891  ConnErrorFlag = true;
4892  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
4893  ConnErrorFlag = true;
4894  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
4895  ConnErrorFlag = true;
4896  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
4897  ConnErrorFlag = true;
4898  }
4899  if(ConnErrorFlag)
4900  {
4901  Utilities->CallLogPop(505);
4902  return false;
4903  }
4904 
4905  bool CLkErrorFlag = false;
4906 
4907  for(unsigned int x = 0; x < TrackVector.size(); x++)
4908  {
4909  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
4910  CLkErrorFlag = true;
4911  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
4912  CLkErrorFlag = true;
4913  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
4914  CLkErrorFlag = true;
4915  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
4916  CLkErrorFlag = true;
4917  }
4918 
4919  if(CLkErrorFlag)
4920  {
4921  Utilities->CallLogPop(506);
4922  return false;
4923  }
4924  Utilities->CallLogPop(507);
4925  return true;
4926 }
4927 
4928 // ---------------------------------------------------------------------------
4929 
4931 {
4932  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
4933  int Position1, Position2;
4934  TTrackElement TrackElement1, TrackElement2;
4935  TGapMapIterator GapMapPtr;
4936 
4937  if(!GapMap.empty())
4938  {
4939  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
4940  {
4941  int HLoc1 = GapMapPtr->first.first;
4942  int VLoc1 = GapMapPtr->first.second;
4943  int HLoc2 = GapMapPtr->second.first;
4944  int VLoc2 = GapMapPtr->second.second;
4945  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
4946  {
4947  throw Exception("Failed to find H & V for gap1, GapMap in error");
4948  }
4949  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
4950  {
4951  throw Exception("Failed to find H & V for gap2, GapMap in error");
4952  }
4953  if(TrackElementAt(9, Position1).TrackType != GapJump)
4954  {
4955  throw Exception("Element at Pos1 not a gap, GapMap in error");
4956  }
4957  if(TrackElementAt(10, Position2).TrackType != GapJump)
4958  {
4959  throw Exception("Element at Pos2 not a gap, GapMap in error");
4960  }
4961  TrackElementAt(11, Position1).Conn[0] = Position2;
4962  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
4963  TrackElementAt(13, Position2).Conn[0] = Position1;
4964  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
4965  }
4966  }
4967  Utilities->CallLogPop(510);
4968  return true;
4969 }
4970 
4971 // ---------------------------------------------------------------------------
4972 
4973 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
4974 {
4975 // TIMPair MapEntry;
4976  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
4977  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
4978  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
4979  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
4980  TLocationNameMultiMapEntry LocationNameEntry;
4981 
4982  LocationNameEntry.first = TrackElement.LocationName;
4983  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
4984  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
4985  {
4986 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
4987 // could arise when loading old railways with multiple NonStationNamedLocs
4988  bool FoundFlag = false;
4989  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
4990  if(FoundFlag)
4991  {
4992  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
4993  IMPair.second).SpeedTag == TrackElement.SpeedTag))
4994  {
4995  Utilities->CallLogPop(1813);
4996  return;
4997  }
4998  }
4999  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
5000  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
5001  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5002  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5003  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5004  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5005  if(TrackElement.FixedNamedLocationElement)
5006  {
5007  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5008  LocationNameMultiMap.insert(LocationNameEntry);
5009  }
5010  if(TrackElement.HLoc < HLocMin)
5011  HLocMin = TrackElement.HLoc;
5012  if(TrackElement.HLoc > HLocMax)
5013  HLocMax = TrackElement.HLoc;
5014  if(TrackElement.VLoc < VLocMin)
5015  VLocMin = TrackElement.VLoc;
5016  if(TrackElement.VLoc > VLocMax)
5017  VLocMax = TrackElement.VLoc;
5018  }
5019  else
5020  {
5021 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5022 // shouldn't arise but leave in as a safeguard
5023  bool FoundFlag = false;
5024  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5025  if(FoundFlag)
5026  {
5027  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5028  {
5029  Utilities->CallLogPop(1814);
5030  return;
5031  }
5032  }
5033  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5034  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5035  {
5036  TrackMapKeyPair.first = TrackElement.HLoc;
5037  TrackMapKeyPair.second = TrackElement.VLoc;
5038  TrackMapEntry.first = TrackMapKeyPair;
5039  TrackMapEntry.second = TrackVector.size() - 1;
5040  TrackMap.insert(TrackMapEntry);
5041  if(TrackElement.FixedNamedLocationElement)
5042  {
5043  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap TrackVector.size = Required value + 1, so ...second = -1-Requ'd value
5044  LocationNameMultiMap.insert(LocationNameEntry);
5045  }
5046  if(TrackElement.HLoc < HLocMin)
5047  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5048  if(TrackElement.HLoc > HLocMax)
5049  HLocMax = TrackElement.HLoc;
5050  if(TrackElement.VLoc < VLocMin)
5051  VLocMin = TrackElement.VLoc;
5052  if(TrackElement.VLoc > VLocMax)
5053  VLocMax = TrackElement.VLoc;
5054  }
5055  }
5056 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5057 // CheckMapAndInactiveTrack(6);//test
5058 
5059 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5060 // with the Platforms until layout fully loaded
5061  Utilities->CallLogPop(511);
5062 }
5063 
5064 // ---------------------------------------------------------------------------
5065 
5066 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5067 {
5068  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5069  AnsiString(VLoc));
5070  THVPair TrackMapKeyPair;
5071 
5072  FoundFlag = false;
5073  TTrackMapIterator TrackMapPtr;
5074 
5075  TrackMapKeyPair.first = HLoc;
5076  TrackMapKeyPair.second = VLoc;
5077  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5078  if(TrackMapPtr == TrackMap.end())
5079  {
5080  Utilities->CallLogPop(512);
5081  return -1; // nothing found
5082  }
5083  else
5084  {
5085  FoundFlag = true;
5086  Utilities->CallLogPop(513);
5087  return TrackMapPtr->second;
5088  }
5089 }
5090 
5091 // ---------------------------------------------------------------------------
5092 
5093 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5094 {
5095  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5096  AnsiString(VLoc));
5097  THVPair TrackMapKeyPair;
5098  TTrackMapIterator TrackMapPtr;
5099 
5100  TrackMapKeyPair.first = HLoc;
5101  TrackMapKeyPair.second = VLoc;
5102  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5103  if(TrackMapPtr == TrackMap.end())
5104  {
5105  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5106  throw Exception(Message);
5107  }
5108  else
5109  {
5110  Utilities->CallLogPop(1943);
5111  return TrackElementAt(871, TrackMapPtr->second);
5112  }
5113 }
5114 
5115 // ---------------------------------------------------------------------------
5116 
5118 {
5119  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5120  AnsiString(VLoc));
5121  THVPair InactiveTrackMapKeyPair;
5122  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5123 
5124  InactiveTrackMapKeyPair.first = HLoc;
5125  InactiveTrackMapKeyPair.second = VLoc;
5126  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5127  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5128  {
5129  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5130  throw Exception(Message);
5131  }
5132  else
5133  {
5134  Utilities->CallLogPop(1949);
5135  return InactiveTrackElementAt(34, InactiveTrackMapPtr->second);
5136  }
5137 }
5138 
5139 // ---------------------------------------------------------------------------
5140 
5141 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5142 {
5143  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5144  bool Present = true;
5145  THVPair TrackMapKeyPair;
5146  TTrackMapIterator TrackMapPtr;
5147 
5148  TrackMapKeyPair.first = HLoc;
5149  TrackMapKeyPair.second = VLoc;
5150  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5151  if(TrackMapPtr == TrackMap.end())
5152  {
5153  Present = false;
5154  }
5155  Utilities->CallLogPop(2057);
5156  return Present;
5157 }
5158 
5159 // ---------------------------------------------------------------------------
5160 
5161 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5162 {
5163  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5164  AnsiString(VLoc));
5165  bool Present = true;
5166  THVPair InactiveTrackMapKeyPair;
5167  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5168 
5169  InactiveTrackMapKeyPair.first = HLoc;
5170  InactiveTrackMapKeyPair.second = VLoc;
5171  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5172  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5173  {
5174  Present = false;
5175  }
5176  Utilities->CallLogPop(2058);
5177  return Present;
5178 }
5179 
5180 // ---------------------------------------------------------------------------
5181 
5182 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5183  // max number of elements is 2, for platforms
5184  // note that both elements of RetPair may be the same, if only one present in map
5185 {
5186  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5187  AnsiString(VLoc));
5188  THVPair InactiveTrackMapKeyPair;
5189  TIMPair RetPair;
5190  TInactiveTrackRange InactiveTrackRange;
5191 
5192  FoundFlag = false;
5193  InactiveTrackMapKeyPair.first = HLoc;
5194  InactiveTrackMapKeyPair.second = VLoc;
5195  if(InactiveTrack2MultiMap.empty())
5196  {
5197  RetPair.first = 0;
5198  RetPair.second = 0;
5199  Utilities->CallLogPop(1815);
5200  return RetPair; // map empty
5201  }
5202  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
5203  if(InactiveTrackRange.first == InactiveTrackRange.second)
5204  {
5205  RetPair.first = 0;
5206  RetPair.second = 0;
5207  Utilities->CallLogPop(514);
5208  return RetPair; // nothing found
5209  }
5210  else
5211  {
5212  RetPair.first = InactiveTrackRange.first->second;
5213  RetPair.second = (--InactiveTrackRange.second)->second;
5214  FoundFlag = true;
5215  Utilities->CallLogPop(515);
5216  return RetPair;
5217  }
5218 }
5219 
5220 // ---------------------------------------------------------------------------
5221 
5222 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
5223 {
5224 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
5225  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
5226  AnsiString(DivergingPosition));
5227  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
5228  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
5229  int SpeedTag1 = T1.SpeedTag;
5230  int SpeedTag2 = T2.SpeedTag;
5231 
5232  if(T1.Attribute != T2.Attribute)
5233  {
5234  Utilities->CallLogPop(516);
5235  return false;
5236  }
5237  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
5238  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
5239  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
5240  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
5241  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
5242  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
5243  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
5244  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
5245  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
5246  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
5247  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
5248  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
5249  {
5250  Utilities->CallLogPop(517);
5251  return true;
5252  }
5253  else
5254  {
5255  Utilities->CallLogPop(518);
5256  return false;
5257  }
5258 }
5259 
5260 // ---------------------------------------------------------------------------
5261 
5262 /*
5263  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
5264  {
5265  if(lower.second < higher.second) return true;
5266  else if(lower.second > higher.second) return false;
5267  else if(lower.second == higher.second)
5268  {
5269  if(lower.first < higher.first) return true;
5270  }
5271  return false;
5272  }
5273 */
5274 // ---------------------------------------------------------------------------
5275 
5276 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5277  // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
5278 {
5279  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
5280  if(TrackElement.TrackType != GapJump)
5281  {
5282  throw Exception("Error, Wrong track type in PlotGap");
5283  }
5284  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
5285  {
5286  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
5287  }
5288  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
5289  {
5290  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
5291  }
5292  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
5293  {
5294  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
5295  }
5296  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
5297  {
5298  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
5299  }
5300  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
5301  {
5302  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
5303  }
5304  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
5305  {
5306  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
5307  }
5308  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
5309  {
5310  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
5311  }
5312  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
5313  {
5314  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
5315  }
5316  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
5317  {
5318  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
5319  }
5320  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
5321  {
5322  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
5323  }
5324  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
5325  {
5326  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
5327  }
5328  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
5329  {
5330  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
5331  }
5332  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
5333  {
5334  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
5335  }
5336  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
5337  {
5338  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
5339  }
5340  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
5341  {
5342  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
5343  }
5344  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
5345  {
5346  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
5347  }
5348  Utilities->CallLogPop(1101);
5349 }
5350 
5351 // ---------------------------------------------------------------------------
5352 
5353 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
5354 {
5355  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
5356  if(TrackElement.TrackType != Points)
5357  {
5358  throw Exception("Error, Wrong track type in PlotPoints");
5359  }
5360  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
5361  TrackElement.PlotVariableTrackElement(4, Disp);
5362  if(BothFillets)
5363  {
5364  if(TrackElement.SpeedTag < 28)
5365  {
5366  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
5367  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
5368  }
5369  else if(TrackElement.SpeedTag < 132)
5370  {
5371  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
5372  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
5373  }
5374  else
5375  {
5376  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
5377  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
5378  }
5379  }
5380  else
5381  {
5382  if(TrackElement.SpeedTag < 28)
5383  {
5384  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5385  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
5386  }
5387  else if(TrackElement.SpeedTag < 132)
5388  {
5389  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5390  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
5391  }
5392  else
5393  {
5394  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5395  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
5396  }
5397  }
5398 // replot platform if required
5399  TIMPair IMPair;
5400  bool FoundFlag;
5401 
5402  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5403  if(FoundFlag)
5404  { // only one platform possible at points so only need to plot IMPair.first
5405  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
5406  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
5407  }
5408  Utilities->CallLogPop(519);
5409 }
5410 
5411 // ---------------------------------------------------------------------------
5412 
5413 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5414 {
5415 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
5416  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
5417  if(TrackElement.TrackType != SignalPost)
5418  {
5419  throw Exception("Error, Wrong track type in PlotSignal");
5420  }
5421  for(int x = 0; x < 40; x++)
5422  {
5423  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
5424  {
5425  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
5426  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
5427 // in case existing signal is a double yellow
5428  // plot platforms if present
5429 // Graphics::TBitmap* SignalPlatformGraphic;
5430 // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
5431 // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
5432 // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
5433 // to not be plotted with the above function.
5434  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
5435  // now plot signal (double yellow overwrites most of signal platform if present)
5436  // additions at version 0.6 for other aspects & ground sigs
5437  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
5438  {
5439  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
5440  }
5441  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
5442  {
5443  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
5444  }
5445  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
5446  {
5447  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
5448  }
5449  else // 4 aspect
5450  {
5451  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
5452  }
5453  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
5454  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
5455  {
5456  if(TrackElement.SpeedTag == 68)
5457  {
5458  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
5459  }
5460  if(TrackElement.SpeedTag == 69)
5461  {
5462  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
5463  }
5464  if(TrackElement.SpeedTag == 70)
5465  {
5466  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
5467  }
5468  if(TrackElement.SpeedTag == 71)
5469  {
5470  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
5471  }
5472  if(TrackElement.SpeedTag == 72)
5473  {
5474  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
5475  }
5476  if(TrackElement.SpeedTag == 73)
5477  {
5478  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
5479  }
5480  if(TrackElement.SpeedTag == 74)
5481  {
5482  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
5483  }
5484  if(TrackElement.SpeedTag == 75)
5485  {
5486  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
5487  }
5488  }
5489  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
5490  // ground signal calling on, need to use normal proceed aspect
5491  {
5492  for(int x = 0; x < 40; x++)
5493  {
5494  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
5495  {
5496  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
5497  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
5498  // plot special signal platform if present
5499  Graphics::TBitmap* SignalPlatformGraphic;
5500  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
5501  // now plot signal
5502  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
5503  }
5504  }
5505  }
5506  break;
5507  }
5508  }
5509  Utilities->CallLogPop(520);
5510 }
5511 
5512 // ---------------------------------------------------------------------------
5513 
5514 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
5515 {
5516  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5517  bool FoundFlag;
5518  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
5519 
5520  if(!FoundFlag)
5521  {
5522  Utilities->CallLogPop(2112);
5523  return;
5524  }
5525  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
5526  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
5527 
5528  // don't want 'else if' for the below as may need to plot 2 platforms
5529  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
5530  {
5531  if(IAElement1.LocationName == "") // '2' will be same
5532  {
5533  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
5534  }
5535  else
5536  {
5537  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
5538  }
5539  }
5540  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
5541  {
5542  if(IAElement1.LocationName == "") // '2' will be same
5543  {
5544  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
5545  }
5546  else
5547  {
5548  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
5549  }
5550  }
5551  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
5552  {
5553  if(IAElement1.LocationName == "") // '2' will be same
5554  {
5555  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
5556  }
5557  else
5558  {
5559  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
5560  }
5561  }
5562  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
5563  {
5564  if(IAElement1.LocationName == "") // '2' will be same
5565  {
5566  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
5567  }
5568  else
5569  {
5570  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
5571  }
5572  }
5573  Utilities->CallLogPop(2113);
5574 }
5575 
5576 // ---------------------------------------------------------------------------
5577 
5578 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
5579 {
5580 // Set attrs to 0=closed to trains; 1=open to trains; 2 = changing = closed to trains
5581  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
5582  AnsiString(VLoc));
5583 // find topmost LC, opening them all (to trains) in turn
5584  int UpStep = 0;
5585 
5586  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
5587  {
5588  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
5589  UpStep--;
5590  }
5591 // now find bottommost LC, opening them all (to trains) in turn
5592  int DownStep = 1;
5593 
5594  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
5595  {
5596  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
5597  DownStep++;
5598  }
5599 // find leftmost LC, opening them all (to trains) in turn
5600  int LeftStep = 0;
5601 
5602  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
5603  {
5604  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
5605  LeftStep--;
5606  }
5607 // now find rightmost LC, opening them all (to trains) in turn
5608  int RightStep = 1;
5609 
5610  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
5611  {
5612  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
5613  RightStep++;
5614  }
5615  Utilities->CallLogPop(1915);
5616 }
5617 
5618 // ---------------------------------------------------------------------------
5619 
5620 void TTrack::SetLinkedManualLCs(int Caller, int HLoc, int VLoc) //sets TypeOfRoute to 2 for all linked LCs
5621 {
5622  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLinkedManualLCs," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5623 // work upwards setting all to manual
5624  int UpStep = -1;
5625 
5626  while(IsLCAtHV(51, HLoc, (VLoc + UpStep)))
5627  {
5628  SetBarriersDownLCToManual(0, HLoc, (VLoc + UpStep));
5629  UpStep--;
5630  }
5631 // work downwards setting all to manual
5632  int DownStep = 1;
5633 
5634  while(IsLCAtHV(52, HLoc, (VLoc + DownStep)))
5635  {
5636  SetBarriersDownLCToManual(1, HLoc, (VLoc + DownStep));
5637  DownStep++;
5638  }
5639 // work leftwards setting all to manual
5640  int LeftStep = -1;
5641 
5642  while(IsLCAtHV(53, (HLoc + LeftStep), VLoc))
5643  {
5644  SetBarriersDownLCToManual(2, (HLoc + LeftStep), VLoc);
5645  LeftStep--;
5646  }
5647 // work rightwards setting all to manual
5648  int RightStep = 1;
5649 
5650  while(IsLCAtHV(54, (HLoc + RightStep), VLoc))
5651  {
5652  SetBarriersDownLCToManual(3, (HLoc + RightStep), VLoc);
5653  RightStep++;
5654  }
5655  Utilities->CallLogPop(2242);
5656 }
5657 
5658 // ---------------------------------------------------------------------------
5659 
5660 void TTrack::SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
5661 {// Set TypeOfRoute value to 2 to indicate barriers manually closed
5662  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetBarriersDownLCToManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5663  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
5664  {
5665  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc))
5666  {
5667  BarriersDownVector.at(x).TypeOfRoute = 2;
5668  break;
5669  }
5670  }
5671  Utilities->CallLogPop(2243);
5672 }
5673 
5674 // ---------------------------------------------------------------------------
5675 
5676 bool TTrack::AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
5677 {
5678  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedBarrierDownVectorManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5679 // work upwards
5680  int UpStep = 0; //start with this location
5681 
5682  while(IsLCAtHV(55, HLoc, (VLoc + UpStep)))
5683  {
5684  if(IsBarrierDownVectorAtHVManual(0, HLoc, (VLoc + UpStep), BDVectorPos))
5685  {
5686  Utilities->CallLogPop(2244);
5687  return true;
5688  }
5689  UpStep--;
5690  }
5691 // work downwards
5692  int DownStep = 1;
5693 
5694  while(IsLCAtHV(56, HLoc, (VLoc + DownStep)))
5695  {
5696  if(IsBarrierDownVectorAtHVManual(1, HLoc, (VLoc + DownStep), BDVectorPos))
5697  {
5698  Utilities->CallLogPop(2245);
5699  return true;
5700  }
5701  DownStep++;
5702  }
5703 // work leftwards
5704  int LeftStep = -1;
5705 
5706  while(IsLCAtHV(57, (HLoc + LeftStep), VLoc))
5707  {
5708  if(IsBarrierDownVectorAtHVManual(2, (HLoc + LeftStep), VLoc, BDVectorPos))
5709  {
5710  Utilities->CallLogPop(2246);
5711  return true;
5712  }
5713  LeftStep--;
5714  }
5715 // work rightwards
5716  int RightStep = 1;
5717 
5718  while(IsLCAtHV(58, (HLoc + RightStep), VLoc))
5719  {
5720  if(IsBarrierDownVectorAtHVManual(3, (HLoc + RightStep), VLoc, BDVectorPos))
5721  {
5722  Utilities->CallLogPop(2247);
5723  return true;
5724  }
5725  RightStep++;
5726  }
5727  Utilities->CallLogPop(2248);
5728  return false;
5729 }
5730 
5731 // ---------------------------------------------------------------------------
5732 
5733 bool TTrack::IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
5734 {
5735  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierDownVectorAtHVManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5736  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
5737  {
5738  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc) && (BarriersDownVector.at(x).TypeOfRoute == 2))
5739  {
5740  BDVectorPos = x;
5741  Utilities->CallLogPop(2249);
5742  return true;
5743  }
5744  }
5745  BDVectorPos = -1;
5746  Utilities->CallLogPop(2250);
5747  return false;
5748 }
5749 
5750 // ---------------------------------------------------------------------------
5751 
5752 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
5753  // open to trains
5754  // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
5755 {
5756  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
5757  AnsiString(VLoc));
5758  if(!IsLCAtHV(4, HLoc, VLoc))
5759  {
5760  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
5761  }
5762  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
5763  {
5764  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
5765  }
5766 // check for adjacent LCs & if so open (to trains)
5767  if(BaseElementSpeedTag == 1) // hor track element
5768  {
5769  // find topmost LC, opening them all (to trains) in turn
5770  int UpStep = 0;
5771  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
5772  {
5773  UpStep--;
5774  }
5775  UpStep++;
5776  // now find bottommost LC, opening them all (to trains) in turn
5777  int DownStep = 1;
5778  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
5779  {
5780  DownStep++;
5781  }
5782  DownStep--;
5783  // now plot graphics, UpStep is smallest & DownStep largest
5784  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
5785  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
5786  Graphics::TBitmap *RouteGraphic;
5787  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
5788  if(TypeOfRoute == 1)
5789  {
5790  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
5791  }
5792  else if(TypeOfRoute == 0)
5793  {
5794  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
5795  }
5796  else //manual - no route
5797  {
5798  RouteGraphic = BaseGraphic;
5799  }
5800 // LinkSigRouteGraphicsPtr[0] hor } pref dir
5801 // LinkSigRouteGraphicsPtr[1] ver }
5802 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
5803 // LinkNonSigRouteGraphicsPtr[1] ver }
5804 
5805  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
5806  {
5807  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5808  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
5809  if(!Manual)
5810  {
5811  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
5812  }
5813  else
5814  {
5815  Disp->PlotOutput(247, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
5816  }
5817  }
5818  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
5819  {
5820  if(UpStep == 0)
5821  {
5822  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5823  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
5824  if(!Manual)
5825  {
5826  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5827  }
5828  else
5829  {
5830  Disp->PlotOutput(248, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
5831  }
5832  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5833  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
5834  if(!Manual)
5835  {
5836  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5837  }
5838  else
5839  {
5840  Disp->PlotOutput(249, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
5841  }
5842  }
5843  else
5844  {
5845  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5846  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
5847  if(!Manual)
5848  {
5849  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5850  }
5851  else
5852  {
5853  Disp->PlotOutput(250, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
5854  }
5855  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5856  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
5857  if(!Manual)
5858  {
5859  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5860  }
5861  else
5862  {
5863  Disp->PlotOutput(251, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
5864  }
5865  }
5866  }
5867  else // at least one plain graphic
5868  {
5869  if(UpStep == 0)
5870  {
5871  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5872  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
5873  if(!Manual)
5874  {
5875  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5876  }
5877  else
5878  {
5879  Disp->PlotOutput(252, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
5880  }
5881  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5882  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
5883  if(!Manual)
5884  {
5885  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5886  }
5887  else
5888  {
5889  Disp->PlotOutput(253, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
5890  }
5891  }
5892  else if(DownStep == 0)
5893  {
5894  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5895  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
5896  if(!Manual)
5897  {
5898  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5899  }
5900  else
5901  {
5902  Disp->PlotOutput(254, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
5903  }
5904  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5905  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
5906  if(!Manual)
5907  {
5908  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5909  }
5910  else
5911  {
5912  Disp->PlotOutput(255, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
5913  }
5914  }
5915  else
5916  {
5917  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5918  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
5919  if(!Manual)
5920  {
5921  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5922  }
5923  else
5924  {
5925  Disp->PlotOutput(256, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
5926  }
5927  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5928  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
5929  if(!Manual)
5930  {
5931  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5932  }
5933  else
5934  {
5935  Disp->PlotOutput(257, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
5936  }
5937  }
5938  for(int x = (UpStep + 1); x < DownStep; x++)
5939  {
5940  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
5941  if(x == 0)
5942  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
5943  else
5944  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
5945  if(!Manual)
5946  {
5947  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
5948  }
5949  else
5950  {
5951  Disp->PlotOutput(258, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
5952  }
5953  }
5954  }
5955  Disp->Update();
5956  Utilities->CallLogPop(1958);
5957  return;
5958  }
5959 
5960  else // ver track element
5961  {
5962  // find leftmost LC, opening them all (to trains) in turn
5963  int LStep = 0;
5964  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
5965  {
5966  LStep--;
5967  }
5968  LStep++;
5969  // now find rightmost LC, opening them all (to trains) in turn
5970  int RStep = 1;
5971  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
5972  {
5973  RStep++;
5974  }
5975  RStep--;
5976  // now plot graphics, LStep is smallest & RStep largest
5977  Graphics::TBitmap *RouteGraphic;
5978  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
5979  if(TypeOfRoute == 1)
5980  {
5981  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
5982  }
5983  else if(TypeOfRoute == 0)
5984  {
5985  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
5986  }
5987  else //manual
5988  {
5989  RouteGraphic = BaseGraphic;
5990  }
5991 // LinkSigRouteGraphicsPtr[0] hor } pref dir
5992 // LinkSigRouteGraphicsPtr[1] ver }
5993 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
5994 // LinkNonSigRouteGraphicsPtr[1] ver }
5995  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
5996  {
5997  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5998  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
5999  if(!Manual)
6000  {
6001  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6002  }
6003  else
6004  {
6005  Disp->PlotOutput(259, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6006  }
6007  }
6008  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6009  {
6010  if(LStep == 0)
6011  {
6012  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6013  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6014  if(!Manual)
6015  {
6016  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6017  }
6018  else
6019  {
6020  Disp->PlotOutput(260, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6021  }
6022  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6023  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6024  if(!Manual)
6025  {
6026  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6027  }
6028  else
6029  {
6030  Disp->PlotOutput(261, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6031  }
6032  }
6033  else
6034  {
6035  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6036  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6037  if(!Manual)
6038  {
6039  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6040  }
6041  else
6042  {
6043  Disp->PlotOutput(262, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6044  }
6045  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6046  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6047  if(!Manual)
6048  {
6049  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6050  }
6051  else
6052  {
6053  Disp->PlotOutput(263, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6054  }
6055  }
6056  }
6057  else // at least one plain graphic
6058  {
6059  if(LStep == 0)
6060  {
6061  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6062  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6063  if(!Manual)
6064  {
6065  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6066  }
6067  else
6068  {
6069  Disp->PlotOutput(264, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6070  }
6071  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6072  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6073  if(!Manual)
6074  {
6075  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6076  }
6077  else
6078  {
6079  Disp->PlotOutput(265, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6080  }
6081  }
6082  else if(RStep == 0)
6083  {
6084  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6085  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6086  if(!Manual)
6087  {
6088  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6089  }
6090  else
6091  {
6092  Disp->PlotOutput(266, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6093  }
6094  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6095  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6096  if(!Manual)
6097  {
6098  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6099  }
6100  else
6101  {
6102  Disp->PlotOutput(267, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6103  }
6104  }
6105  else
6106  {
6107  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6108  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6109  if(!Manual)
6110  {
6111  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6112  }
6113  else
6114  {
6115  Disp->PlotOutput(268, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6116  }
6117  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6118  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6119  if(!Manual)
6120  {
6121  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6122  }
6123  else
6124  {
6125  Disp->PlotOutput(269, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6126  }
6127  }
6128  for(int x = (LStep + 1); x < RStep; x++)
6129  {
6130  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6131  if(x == 0)
6132  {
6133  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
6134  }
6135  else
6136  {
6137  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
6138  }
6139  if(!Manual)
6140  {
6141  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6142  }
6143  else
6144  {
6145  Disp->PlotOutput(270, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6146  }
6147  }
6148  }
6149  Disp->Update();
6150  Utilities->CallLogPop(1896);
6151  return;
6152  }
6153 }
6154 
6155 // ---------------------------------------------------------------------------
6156 
6157 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual) // open to trains
6158  // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6159 {
6160  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
6161  AnsiString(HLoc) + "," + AnsiString(VLoc));
6162  if(!IsLCAtHV(29, HLoc, VLoc))
6163  {
6164  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6165  }
6166  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6167  {
6168  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6169  }
6170 // check for adjacent LCs & if so open (to trains)
6171  if(BaseElementSpeedTag == 1) // hor track element
6172  {
6173  // find topmost LC, opening them all (to trains) in turn
6174  int UpStep = 0;
6175  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6176  {
6177  UpStep--;
6178  }
6179  UpStep++;
6180  // now find bottommost LC, opening them all (to trains) in turn
6181  int DownStep = 1;
6182  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
6183  {
6184  DownStep++;
6185  }
6186  DownStep--;
6187  // now plot graphics, UpStep is smallest & DownStep largest
6188  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6189  {
6190  if(!Manual)
6191  {
6192  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6193  }
6194  else
6195  {
6196  Disp->PlotOutput(271, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6197  }
6198  }
6199  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6200  {
6201  if(!Manual)
6202  {
6203  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6204  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6205  }
6206  else
6207  {
6208  Disp->PlotOutput(272, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6209  Disp->PlotOutput(273, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6210  }
6211  }
6212  else // at least one plain graphic
6213  {
6214  if(!Manual)
6215  {
6216  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6217  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6218  for(int x = (UpStep + 1); x < DownStep; x++)
6219  {
6220  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6221  }
6222  }
6223  else
6224  {
6225  Disp->PlotOutput(274, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6226  Disp->PlotOutput(275, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6227  for(int x = (UpStep + 1); x < DownStep; x++)
6228  {
6229  Disp->PlotOutput(276, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6230  }
6231  }
6232  }
6233  // set markers
6234  for(int x = UpStep; x <= DownStep; x++)
6235  {
6236  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).LCPlotted = true; // plotted
6237  }
6238  Display->Update();
6239  Utilities->CallLogPop(1944);
6240  return;
6241  }
6242 
6243  else // ver track element
6244  {
6245  // find leftmost LC, opening them all (to trains) in turn
6246  int LStep = 0;
6247  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
6248  {
6249  LStep--;
6250  }
6251  LStep++;
6252  // now find rightmost LC, opening them all (to trains) in turn
6253  int RStep = 1;
6254  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
6255  {
6256  RStep++;
6257  }
6258  RStep--;
6259  // now plot graphics, LStep is smallest & RStep largest
6260  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6261  {
6262  if(!Manual)
6263  {
6264  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6265  }
6266  else
6267  {
6268  Disp->PlotOutput(277, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6269  }
6270  }
6271  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6272  {
6273  if(!Manual)
6274  {
6275  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6276  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6277  }
6278  else
6279  {
6280  Disp->PlotOutput(278, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6281  Disp->PlotOutput(279, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6282  }
6283  }
6284  else // at least one plain graphic
6285  {
6286  if(!Manual)
6287  {
6288  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6289  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6290  for(int x = (LStep + 1); x < RStep; x++)
6291  {
6292  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6293  }
6294  }
6295  else
6296  {
6297  Disp->PlotOutput(280, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6298  Disp->PlotOutput(281, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6299  for(int x = (LStep + 1); x < RStep; x++)
6300  {
6301  Disp->PlotOutput(282, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6302  }
6303  }
6304  }
6305  // set markers
6306  for(int x = LStep; x <= RStep; x++)
6307  {
6308  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).LCPlotted = true; // plotted
6309  }
6310  Disp->Update();
6311  Utilities->CallLogPop(1945);
6312  return;
6313  }
6314 }
6315 
6316 // ---------------------------------------------------------------------------
6317 
6318 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
6319  // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6320 {
6321  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6322  AnsiString(VLoc));
6323  if(!IsLCAtHV(9, HLoc, VLoc))
6324  {
6325  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
6326  }
6327  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6328  {
6329  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
6330  }
6331 // check for adjacent LCs & if so close (to trains)
6332  if(BaseElementSpeedTag == 1) // hor track element
6333  {
6334  // find topmost LC, closing them all (to trains) in turn
6335  int UpStep = 0;
6336  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6337  {
6338  UpStep--;
6339  }
6340  UpStep++;
6341  // now find bottommost LC, opening them all (to trains) in turn
6342  int DownStep = 1;
6343  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
6344  {
6345  DownStep++;
6346  }
6347  DownStep--;
6348  // now plot graphics, UpStep is smallest & DownStep largest
6349  for(int x = UpStep; x < (DownStep + 1); x++)
6350  {
6351  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6352  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
6353  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
6354  }
6355  Disp->Update();
6356  Utilities->CallLogPop(1959);
6357  return;
6358  }
6359 
6360  else // ver track element
6361  {
6362  // find leftmost LC, closing them all (to trains) in turn
6363  int LStep = 0;
6364  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
6365  {
6366  LStep--;
6367  }
6368  LStep++;
6369  // now find rightmost LC, opening them all (to trains) in turn
6370  int RStep = 1;
6371  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
6372  {
6373  RStep++;
6374  }
6375  RStep--;
6376  // now plot graphics, LStep is smallest & RStep largest
6377  for(int x = LStep; x < (RStep + 1); x++)
6378  {
6379  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6380  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
6381  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
6382  }
6383  Disp->Update();
6384  Utilities->CallLogPop(1960);
6385  return;
6386  }
6387 }
6388 
6389 // ---------------------------------------------------------------------------
6390 
6391 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
6392  // closed to trains
6393  // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6394 {
6395  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
6396  AnsiString(HLoc) + "," + AnsiString(VLoc));
6397  if(!IsLCAtHV(34, HLoc, VLoc))
6398  {
6399  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
6400  }
6401  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6402  {
6403  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
6404  }
6405  TTrackElement TE;
6406 
6407 // check for adjacent LCs & if so close (to trains)
6408  if(BaseElementSpeedTag == 1) // hor track element
6409  {
6410  // find topmost LC, closing them all (to trains) in turn
6411  int UpStep = 0;
6412  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6413  {
6414  UpStep--;
6415  }
6416  UpStep++;
6417  // now find bottommost LC, opening them all (to trains) in turn
6418  int DownStep = 1;
6419  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
6420  {
6421  DownStep++;
6422  }
6423  DownStep--;
6424  // now plot graphics, UpStep is smallest & DownStep largest
6425  for(int x = UpStep; x <= DownStep; x++)
6426  {
6427  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
6428  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).LCPlotted = true; // plotted
6429  }
6430  Display->Update();
6431  Utilities->CallLogPop(1946);
6432  return;
6433  }
6434 
6435  else // ver track element
6436  {
6437  // find leftmost LC, closing them all (to trains) in turn
6438  int LStep = 0;
6439  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
6440  {
6441  LStep--;
6442  }
6443  LStep++;
6444  // now find rightmost LC, opening them all (to trains) in turn
6445  int RStep = 1;
6446  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
6447  {
6448  RStep++;
6449  }
6450  RStep--;
6451  // now plot graphics, LStep is smallest & RStep largest
6452  for(int x = LStep; x <= RStep; x++)
6453  {
6454  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
6455  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).LCPlotted = true; // plotted
6456  }
6457  Display->Update();
6458  Utilities->CallLogPop(1947);
6459  return;
6460  }
6461 }
6462 
6463 // ---------------------------------------------------------------------------
6464 
6465 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
6466 {
6467  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6468  Graphics::TBitmap *RouteGraphic;
6469  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6470 
6471  if(BaseElementSpeedTag == 1)
6472  {
6473  if(TypeOfRoute == 1)
6474  {
6475  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6476  }
6477  else if(TypeOfRoute == 0)
6478  {
6479  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6480  }
6481  else //manual
6482  {
6483  RouteGraphic = BaseGraphic;
6484  }
6485 
6486  if(State == Raising)
6487  RouteGraphic = BaseGraphic;
6488  }
6489  else
6490  {
6491  BaseGraphic = RailGraphics->gl2;
6492  if(TypeOfRoute == 1)
6493  {
6494  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6495  }
6496  else if(TypeOfRoute == 0)
6497  {
6498  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6499  }
6500  else
6501  {
6502  RouteGraphic = BaseGraphic; //manual
6503  }
6504  if(State == Raising)
6505  RouteGraphic = BaseGraphic;
6506  }
6507  int UpStep = 0;
6508 
6509  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6510  {
6511  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6512  if(UpStep == 0)
6513  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6514  else
6515  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6516  UpStep--;
6517  }
6518 // now find bottommost LC, opening them all (to trains) in turn
6519  int DownStep = 1;
6520 
6521  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
6522  {
6523  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6524  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6525  DownStep++;
6526  }
6527  int LeftStep = 0;
6528 
6529  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6530  {
6531  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6532  if(LeftStep == 0)
6533  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
6534  else
6535  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
6536  LeftStep--;
6537  }
6538 // now find rightmost LC, opening them all (to trains) in turn
6539  int RightStep = 1;
6540 
6541  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
6542  {
6543  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6544  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
6545  RightStep++;
6546  }
6547  Disp->Update();
6548  Utilities->CallLogPop(1914);
6549 }
6550 
6551 // ---------------------------------------------------------------------------
6552 
6553 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
6554 {
6555 // return false for no LC there, flashing or a closed (to trains) LC
6556  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6557  bool FoundFlag;
6558  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
6559 
6560  if(!FoundFlag)
6561  {
6562  Utilities->CallLogPop(1898);
6563  return false;
6564  }
6565  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6566  {
6567  Utilities->CallLogPop(1899);
6568  return false;
6569  }
6570  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
6571  {
6572  Utilities->CallLogPop(1900);
6573  return true;
6574  }
6575  Utilities->CallLogPop(1901);
6576  return false;
6577 }
6578 
6579 // ---------------------------------------------------------------------------
6580 
6581 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
6582 {
6583 // return false for no LC there, flashing LC or open (to trains) LC
6584  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6585  bool FoundFlag;
6586  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
6587 
6588  if(!FoundFlag)
6589  {
6590  Utilities->CallLogPop(1922);
6591  return false;
6592  }
6593  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6594  {
6595  Utilities->CallLogPop(1923);
6596  return false;
6597  }
6598  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
6599  {
6600  Utilities->CallLogPop(1924);
6601  return true;
6602  }
6603  Utilities->CallLogPop(1925);
6604  return false;
6605 }
6606 
6607 // ---------------------------------------------------------------------------
6608 
6609 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
6610 {
6611 // return true for barrier in process of moving
6612  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6613  bool FoundFlag;
6614  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
6615 
6616  if(!FoundFlag)
6617  {
6618  Utilities->CallLogPop(1918);
6619  return false;
6620  }
6621  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6622  {
6623  Utilities->CallLogPop(1919);
6624  return false;
6625  }
6626  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
6627  {
6628  Utilities->CallLogPop(1920);
6629  return true;
6630  }
6631  Utilities->CallLogPop(1921);
6632  return false;
6633 }
6634 
6635 // ---------------------------------------------------------------------------
6636 
6637 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
6638 {
6639 // return true for an LC at H&V
6640  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6641  bool FoundFlag;
6642  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
6643 
6644  if(!FoundFlag)
6645  {
6646  Utilities->CallLogPop(1902);
6647  return false;
6648  }
6649  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6650  {
6651  Utilities->CallLogPop(1903);
6652  return false;
6653  }
6654  Utilities->CallLogPop(1904);
6655  return true;
6656 }
6657 
6658 // ---------------------------------------------------------------------------
6659 
6660 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
6661 {
6662  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
6663  AnsiString(Attr));
6664  bool FoundFlag;
6665  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
6666 
6667  if(!FoundFlag)
6668  {
6669  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
6670  }
6671  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6672  {
6673  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
6674  }
6675  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
6676  Utilities->CallLogPop(1905);
6677  return;
6678 }
6679 
6680 // ---------------------------------------------------------------------------
6681 
6683 {
6684  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
6685  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
6686  {
6687  TTrackElement InactiveTrackElement = InactiveTrackVector.at(x);
6688  if(InactiveTrackElement.TrackType == LevelCrossing)
6689  {
6690  InactiveTrackVector.at(x).Attribute = 0;
6691  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
6692  }
6693  }
6694  Utilities->CallLogPop(1913);
6695  return;
6696 }
6697 
6698 // ---------------------------------------------------------------------------
6699 
6700 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, bool &TrainPresent)
6701 {
6702 // return true if there is either a route set on any element or a train on any element
6703  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
6704  "," + AnsiString(VLoc));
6705 
6706  THVPair TrackMapKeyPair;
6707  TTrack::TTrackMapIterator TrackMapPtr;
6708  int DummyRouteNumber;
6709 
6710  TrainPresent = false;
6711 // find topmost LC, checking each for routes & trains
6712  int UpStep = 0;
6713 
6714  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6715  {
6716  TrackMapKeyPair.first = HLoc;
6717  TrackMapKeyPair.second = VLoc + UpStep;
6718  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6719  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
6720  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
6721  {
6722  Utilities->CallLogPop(1932);
6723  return true;
6724  }
6725  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
6726  {
6727  TrainPresent = true;
6728  Utilities->CallLogPop(1933);
6729  return true;
6730  }
6731  UpStep--;
6732  }
6733 // now find bottommost LC, opening them all (to trains) in turn
6734  int DownStep = 1;
6735 
6736  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
6737  {
6738  TrackMapKeyPair.first = HLoc;
6739  TrackMapKeyPair.second = VLoc + DownStep;
6740  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6741  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
6742  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
6743  {
6744  Utilities->CallLogPop(1934);
6745  return true;
6746  }
6747  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
6748  {
6749  TrainPresent = true;
6750  Utilities->CallLogPop(1935);
6751  return true;
6752  }
6753  DownStep++;
6754  }
6755 // find leftmost LC
6756  int LeftStep = 0;
6757 
6758  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6759  {
6760  TrackMapKeyPair.first = HLoc + LeftStep;
6761  TrackMapKeyPair.second = VLoc;
6762  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6763  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
6764  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
6765  {
6766  Utilities->CallLogPop(1936);
6767  return true;
6768  }
6769  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
6770  {
6771  TrainPresent = true;
6772  Utilities->CallLogPop(1937);
6773  return true;
6774  }
6775  LeftStep--;
6776  }
6777 // now find rightmost LC, opening them all (to trains) in turn
6778  int RightStep = 1;
6779 
6780  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
6781  {
6782  TrackMapKeyPair.first = HLoc + RightStep;
6783  TrackMapKeyPair.second = VLoc;
6784  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6785  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
6786  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
6787  {
6788  Utilities->CallLogPop(1938);
6789  return true;
6790  }
6791  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
6792  {
6793  TrainPresent = true;
6794  Utilities->CallLogPop(1939);
6795  return true;
6796  }
6797  RightStep++;
6798  }
6799  Utilities->CallLogPop(1940);
6800  return false;
6801 }
6802 
6803 // ---------------------------------------------------------------------------
6804 
6805 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
6806 {
6807  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
6808  if(TrackElement.TrackType != Points)
6809  {
6810  throw Exception("Error, Wrong track type in GetFilletGraphic");
6811  }
6812  if(TrackElement.SpeedTag < 28)
6813  {
6814  Utilities->CallLogPop(521);
6815  return RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute];
6816  }
6817  else if(TrackElement.SpeedTag < 132)
6818  {
6819  Utilities->CallLogPop(522);
6820 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
6821  return RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute];
6822  }
6823  else
6824  {
6825  Utilities->CallLogPop(1537);
6826  return RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute];
6827  }
6828 }
6829 
6830 // ---------------------------------------------------------------------------
6831 
6833 {
6834  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDElements");
6835  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
6836  {
6837  TrackVector.at(x).TrainIDOnElement = -1;
6838  TrackVector.at(x).TrainIDOnBridgeTrackPos01 = -1;
6839  TrackVector.at(x).TrainIDOnBridgeTrackPos23 = -1;
6840  }
6841  Utilities->CallLogPop(1342);
6842 }
6843 
6844 // ---------------------------------------------------------------------------
6845 
6846 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
6847 /*
6848  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
6849 */
6850 {
6851  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
6852  AnsiString(ScreenPosV));
6853  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
6854  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
6855 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
6856  Utilities->CallLogPop(535);
6857 }
6858 
6859 // ---------------------------------------------------------------------------
6860 
6861 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
6862 /*
6863  Converts the screen position to the true (without offsets) position
6864 */
6865 {
6866  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
6867  AnsiString(ScreenPosV));
6868  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
6869  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
6870  Utilities->CallLogPop(536);
6871 }
6872 
6873 // ---------------------------------------------------------------------------
6874 
6875 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
6876 {
6877  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
6878  AnsiString(VPosTrue));
6879  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
6880  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
6881  Utilities->CallLogPop(537);
6882 }
6883 
6884 // ---------------------------------------------------------------------------
6885 
6886 void TTrack::CheckMapAndTrack(int Caller) // test
6887 {
6888  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
6889  int Zeroes = 0;
6890  bool FoundFlag;
6891 
6892  for(unsigned int a = 0; a < TrackVector.size(); a++)
6893  {
6894  TTrackElement CheckElement = Track->TrackVector.at(a);
6895  if(CheckElement.SpeedTag == 0)
6896  {
6897  Zeroes++; // zeroed elements not saved in map
6898  }
6899  else
6900  {
6901  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
6902  if(!FoundFlag)
6903  {
6904  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
6905  " in TrackMap, Caller=" + (AnsiString)Caller);
6906  }
6907  if(MapVecPos != (int)a)
6908  {
6909  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
6910  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
6911  (AnsiString)Caller);
6912  }
6913  }
6914  }
6915  if(TrackVector.size() != (TrackMap.size() + Zeroes))
6916  {
6917  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
6918  " Caller=" + (AnsiString)Caller);
6919  }
6920  Utilities->CallLogPop(538);
6921  return;
6922 }
6923 
6924 // ---------------------------------------------------------------------------
6925 
6926 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
6927 {
6928  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
6929  bool FoundFlag;
6930  TIMPair InactivePair;
6931 
6932  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
6933  {
6934  TTrackElement CheckElement = Track->InactiveTrackVector.at(a);
6935  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
6936  if(!FoundFlag)
6937  {
6938  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
6939  " in InactiveMap, Caller=" + (AnsiString)Caller);
6940  }
6941  if((InactivePair.first != a) && (InactivePair.second != a))
6942  {
6943  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
6944  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
6945  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
6946  }
6947  }
6948  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
6949  {
6950  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
6951  " Caller=" + (AnsiString)Caller);
6952  }
6953  Utilities->CallLogPop(539);
6954 }
6955 
6956 // ---------------------------------------------------------------------------
6957 
6958 void TTrack::CheckGapMap(int Caller) // test
6959 {
6960  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
6961  int Position1, Position2;
6962  TTrackElement TrackElement1, TrackElement2;
6963  TGapMapIterator GapMapPtr;
6964 
6965  if(!GapMap.empty())
6966  {
6967  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
6968  {
6969  int HLoc1 = GapMapPtr->first.first;
6970  int VLoc1 = GapMapPtr->first.second;
6971  int HLoc2 = GapMapPtr->second.first;
6972  int VLoc2 = GapMapPtr->second.second;
6973  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
6974  {
6975  throw Exception("Failed to find H & V for gap1, GapMap in error");
6976  }
6977  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
6978  {
6979  throw Exception("Failed to find H & V for gap2, GapMap in error");
6980  }
6981  if(TrackElementAt(17, Position1).TrackType != GapJump)
6982  {
6983  throw Exception("Element at Pos1 not a gap, GapMap in error");
6984  }
6985  if(TrackElementAt(18, Position2).TrackType != GapJump)
6986  {
6987  throw Exception("Element at Pos2 not a gap, GapMap in error");
6988  }
6989  }
6990  }
6991  unsigned int GapCount = 0;
6992 
6993  for(unsigned int a = 0; a < TrackVector.size(); a++)
6994  {
6995  TTrackElement CheckElement = Track->TrackVector.at(a);
6996  if(CheckElement.TrackType == GapJump)
6997  GapCount++;
6998  }
6999  if((GapMap.size() * 2) != GapCount)
7000  {
7001  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
7002  (AnsiString)Caller);
7003  }
7004  Utilities->CallLogPop(540);
7005 }
7006 
7007 // ---------------------------------------------------------------------------
7008 
7009 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
7010 {
7011  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
7012  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
7013  {
7014  if(TrackFinished)
7015  {
7016  throw Exception("Error - TrackFinished with erase element still present");
7017  }
7018  Utilities->CallLogPop(541);
7019  return; // erased element, can't set ID
7020  }
7021  AnsiString IDString;
7022 
7023  if(TrackElement.HLoc < 0)
7024  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
7025  else
7026  IDString = AnsiString(TrackElement.HLoc) + "-";
7027  if(TrackElement.VLoc < 0)
7028  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
7029  else
7030  IDString += AnsiString(TrackElement.VLoc);
7031  TrackElement.ElementID = IDString;
7032  Utilities->CallLogPop(542);
7033 }
7034 
7035 // ---------------------------------------------------------------------------
7036 
7037 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
7038 {
7039 // e.g. "8-13", "00008-13", "N43-N127", etc
7040  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString, + String");
7041  int DelimPos;
7042 
7043  for(int x = 1; x < String.Length() + 1; x++)
7044  {
7045  if(String.IsDelimiter("-", x))
7046  {
7047  DelimPos = x;
7048  break;
7049  }
7050  if(x == String.Length())
7051  {
7052  if(GiveMessages)
7053  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
7054  Utilities->CallLogPop(543);
7055  return -1;
7056  }
7057  }
7058  if(DelimPos == 1)
7059  {
7060  if(GiveMessages)
7061  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
7062  Utilities->CallLogPop(544);
7063  return -1;
7064  }
7065  if(DelimPos == String.Length())
7066  {
7067  if(GiveMessages)
7068  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
7069  Utilities->CallLogPop(545);
7070  return -1;
7071  }
7072  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
7073  {
7074  if(GiveMessages)
7075  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
7076  Utilities->CallLogPop(1508);
7077  return -1;
7078  }
7079  int HLoc, VLoc;
7080 
7081  if(String.SubString(1, 1) != "N")
7082  {
7083  for(int x = 1; x < DelimPos; x++)
7084  {
7085  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7086  {
7087  if(GiveMessages)
7088  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7089  Utilities->CallLogPop(546);
7090  return -1;
7091  }
7092  }
7093  }
7094  if(String.SubString(1, 1) == "N")
7095  {
7096  for(int x = 2; x < DelimPos; x++)
7097  {
7098  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7099  {
7100  if(GiveMessages)
7101  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7102  Utilities->CallLogPop(763);
7103  return -1;
7104  }
7105  }
7106  }
7107  if(String.SubString(1, 1) == "N")
7108  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
7109  else
7110  HLoc = String.SubString(1, DelimPos - 1).ToInt();
7111 
7112  if(String.SubString(DelimPos + 1, 1) != "N")
7113  {
7114  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
7115  {
7116  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7117  {
7118  if(GiveMessages)
7119  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7120  Utilities->CallLogPop(547);
7121  return -1;
7122  }
7123  }
7124  }
7125  if(String.SubString(DelimPos + 1, 1) == "N")
7126  {
7127  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
7128  {
7129  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7130  {
7131  if(GiveMessages)
7132  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7133  Utilities->CallLogPop(764);
7134  return -1;
7135  }
7136  }
7137  }
7138  if(String.SubString(DelimPos + 1, 1) == "N")
7139  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
7140  else
7141  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
7142 
7143  THVPair HVPair(HLoc, VLoc);
7144  TTrackMapIterator TrackMapPtr;
7145 
7146  TrackMapPtr = TrackMap.find(HVPair);
7147  if(TrackMapPtr == TrackMap.end())
7148  {
7149  if(GiveMessages)
7150  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
7151  Utilities->CallLogPop(548);
7152  return -1;
7153  }
7154  Utilities->CallLogPop(549);
7155  return TrackMapPtr->second;
7156 }
7157 
7158 // ---------------------------------------------------------------------------
7159 
7160 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
7161 /*
7162  True for linked properly at both ends
7163 */
7164 {
7165  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
7166  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
7167  int HLoc = TrackElement.HLoc;
7168  int VLoc = TrackElement.VLoc;
7169 
7170  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
7171  {
7172  Utilities->CallLogPop(1821);
7173  return false;
7174  }
7175  if(TrackElement.SpeedTag == 129) // vertical footbridge
7176  {
7177  // check top connection
7178  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
7179  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
7180  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
7181  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
7182  {
7183  Utilities->CallLogPop(550);
7184  return false;
7185  }
7186  // check bottom connection
7187  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
7188  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
7189  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
7190  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
7191  {
7192  Utilities->CallLogPop(551);
7193  return false;
7194  }
7195  }
7196  if(TrackElement.SpeedTag == 145) // vertical underpass
7197  {
7198  // check top connection
7199  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
7200  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
7201  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
7202  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
7203  {
7204  Utilities->CallLogPop(2114);
7205  return false;
7206  }
7207  // check bottom connection
7208  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
7209  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
7210  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
7211  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
7212  {
7213  Utilities->CallLogPop(2115);
7214  return false;
7215  }
7216  }
7217  if(TrackElement.SpeedTag == 130) // hor footbridge
7218  {
7219  // check left connection
7220  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
7221  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
7222  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
7223  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
7224  {
7225  Utilities->CallLogPop(552);
7226  return false;
7227  }
7228  // check right connection
7229  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
7230  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
7231  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
7232  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
7233  {
7234  Utilities->CallLogPop(553);
7235  return false;
7236  }
7237  }
7238  if(TrackElement.SpeedTag == 146) // hor u'pass
7239  {
7240  // check left connection
7241  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
7242  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
7243  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
7244  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
7245  {
7246  Utilities->CallLogPop(2116);
7247  return false;
7248  }
7249  // check right connection
7250  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
7251  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
7252  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
7253  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
7254  {
7255  Utilities->CallLogPop(2117);
7256  return false;
7257  }
7258  }
7259  Utilities->CallLogPop(554);
7260  return true;
7261 }
7262 
7263 // ---------------------------------------------------------------------------
7264 
7265 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
7266 /*
7267  return true if the SpeedTag present in the map at H & V
7268 */
7269 {
7270  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7271  AnsiString(SpeedTag));
7272  if(InactiveTrack2MultiMap.empty())
7273  {
7274  Utilities->CallLogPop(555);
7275  return false;
7276  }
7277  THVPair HVPair(HLoc, VLoc);
7279  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
7280  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
7281 
7282  if(HVRange.first == HVRange.second)
7283  {
7284  Utilities->CallLogPop(556);
7285  return false;
7286  }
7287  else
7288  HVIt1 = HVRange.first;
7289  TTrackElement Temp1, Temp2; // test
7290 
7291  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
7292  if(--HVRange.second != HVRange.first)
7293  {
7294  HVIt2 = HVRange.second;
7295  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
7296  }
7297  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
7298  HVIt2->second).SpeedTag == SpeedTag)))
7299  {
7300  Utilities->CallLogPop(557);
7301  return true;
7302  }
7303  else
7304  {
7305  Utilities->CallLogPop(558);
7306  return false;
7307  }
7308 }
7309 
7310 // ---------------------------------------------------------------------------
7311 
7312 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
7313 /*
7314  return true if the SpeedTag present in the map at H & V
7315 */
7316 {
7317  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7318  AnsiString(SpeedTag));
7319  if(TrackMap.empty())
7320  {
7321  Utilities->CallLogPop(559);
7322  return false;
7323  }
7324  THVPair HVPair(HLoc, VLoc);
7325  TTrackMapIterator End = TrackMap.end();
7326  TTrackMapIterator It = End;
7327 
7328  It = TrackMap.find(HVPair);
7329  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
7330  {
7331  Utilities->CallLogPop(560);
7332  return true;
7333  }
7334  else
7335  {
7336  Utilities->CallLogPop(561);
7337  return false;
7338  }
7339 }
7340 
7341 // ---------------------------------------------------------------------------
7342 
7343 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
7344 {
7345 /*
7346  General:
7347  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
7348  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
7349  a NamedNonStationLocation.
7350  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
7351  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
7352  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
7353  platform at that location).
7354 
7355  Linked named location elements are those explained in TTrack::TTrack()
7356 
7357  Detail:
7358  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
7359  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
7360  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
7361  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
7362  work OK! e.g. TrackVector position 0 would be stored as -1, position n would be stored as -1-n. InactiveTrackVector position 0 would be stored as 0.
7363  To recover the true TrackVector position from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
7364 
7365  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
7366  this function a single element should be in the List (normally from the user's selection but can also be from
7367  SearchForAndUpdateLocationName), and the Map is cleared within the function.
7368  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
7369  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
7370  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
7371  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
7372  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
7373  moves them into the Map. At the end all linked elements are in the Map.
7374 
7375  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
7376  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
7377  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
7378 */
7379 
7380 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
7381 // Display->FileDiagnostics(TestString);//test
7382 
7383  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
7384  AnsiString TestString1, TestString2; // test
7385 
7386  Track->LNDone2MultiMap.clear();
7387  if(LNPendingList.size() != 1)
7388  {
7389  throw Exception("LNPendingList size not 1 on entry");
7390  }
7391  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
7392  while(!LNPendingList.empty())
7393  {
7394  CurrentElementNumber = LNPendingList.front();
7395  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
7396  int NewElement; // = 2000000000; //marker for unused //not needed after v1.1.4
7397  int H = CurrentElement->HLoc;
7398  int V = CurrentElement->VLoc;
7399  int Tag = CurrentElement->SpeedTag;
7400  if(Tag == 76) // top plat
7401  {
7402  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
7403  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
7404  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
7405  for(int x = 0; x < 25; x++)
7406  {
7407  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
7408  {
7409  LNPendingList.insert(LNPendingList.end(), NewElement);
7410  }
7411  }
7412  }
7413  else if(Tag == 77) // bot plat
7414  {
7415  for(int x = 0; x < 25; x++)
7416  {
7417  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
7418  {
7419  LNPendingList.insert(LNPendingList.end(), NewElement);
7420  }
7421  }
7422  }
7423  else if(Tag == 78) // l plat
7424  {
7425  for(int x = 0; x < 25; x++)
7426  {
7427  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
7428  {
7429  LNPendingList.insert(LNPendingList.end(), NewElement);
7430  }
7431  }
7432  }
7433  else if(Tag == 79) // r plat
7434  {
7435  for(int x = 0; x < 25; x++)
7436  {
7437  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
7438  {
7439  LNPendingList.insert(LNPendingList.end(), NewElement);
7440  }
7441  }
7442  }
7443  else if(Tag == 96) // conc
7444  {
7445  for(int x = 0; x < 28; x++)
7446  {
7447  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
7448  {
7449  LNPendingList.insert(LNPendingList.end(), NewElement);
7450  }
7451  }
7452  }
7453  else if(Tag == 129) // vert footbridge
7454  {
7455  for(int x = 0; x < 8; x++)
7456  {
7457  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
7458  {
7459  LNPendingList.insert(LNPendingList.end(), NewElement);
7460  }
7461  }
7462  }
7463  else if(Tag == 130) // hor footbridge
7464  {
7465  for(int x = 0; x < 8; x++)
7466  {
7467  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
7468  {
7469  LNPendingList.insert(LNPendingList.end(), NewElement);
7470  }
7471  }
7472  }
7473  else if(Tag == 131) // named location
7474  {
7475  for(int x = 0; x < 4; x++)
7476  {
7477  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
7478  {
7479  LNPendingList.insert(LNPendingList.end(), NewElement);
7480  }
7481  }
7482  }
7483  else if(Tag == 145) // v u'pass
7484  {
7485  for(int x = 0; x < 8; x++)
7486  {
7487  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
7488  {
7489  LNPendingList.insert(LNPendingList.end(), NewElement);
7490  }
7491  }
7492  }
7493  else if(Tag == 146) // h u'pass
7494  {
7495  for(int x = 0; x < 8; x++)
7496  {
7497  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
7498  {
7499  LNPendingList.insert(LNPendingList.end(), NewElement);
7500  }
7501  }
7502  }
7503  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
7504 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
7505  if(AddingElements)
7506  {
7507  int HPos, VPos; // not used but needed for FindText function
7508  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
7509  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
7510  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
7511  {
7512  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName;//existing name of CurrentElement
7513  if((ExistingName != "") && (ExistingName != LocationName))
7514  {
7515  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
7516  {} // name not in LocationNameMultiMap, so don't erase from TextVector
7517  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
7518  {
7519  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
7520  {;
7521  } // condition not used
7522  }
7523  }
7524  }
7525  }
7526 
7527  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
7528  // track at that loc
7529  THVPair HVPair(H, V);
7530  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
7531  LNDone2MultiMapEntry.first = HVPair;
7532  LNDone2MultiMapEntry.second = LNPendingList.front();
7533  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
7534  LNPendingList.erase(LNPendingList.begin());
7535  }
7536 
7537 // search all name multimap for same name where corresponding active elements don't appear in
7538 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
7539 
7540  TLocationNameMultiMapIterator SNIterator;
7541  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
7542  bool FoundFlag, ErasedFlag = false;
7543 
7544  if(SNRange.first != SNRange.second)
7545  {
7546  SNRange.first--; // now pointing to before the first
7547  SNRange.second--; // now pointing to the last
7548  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
7549  // Same elements are in Done map as in name map
7550  {
7551  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
7552  {
7553  ErasedFlag = true;
7554  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
7555  TVIt->LocationName = "";
7556  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
7557  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
7558  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
7559  {
7560  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
7561  if(FoundFlag)
7562  {
7563  TrackElementAt(20, Position).LocationName = "";
7564  TrackElementAt(21, Position).ActiveTrackElementName = "";
7565  }
7566  }
7567  // erase name in name map
7568 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
7569  }
7570  }
7571  }
7572  if(ErasedFlag)
7574  if(TrackFinished)
7576 // set here as well as in LinkTrack so don't have to link track just because a name added
7577 // if track not finished then will be set when track validated
7578 
7579 // Rebuild ContinuationNameMap - added at v2.6.1 due to error found by Andrekoener & notified by discord on 16/12/20
7580 // error was that if a continuation name was changed and a timetable stopping place included that new name then ContinuationNameMap wouldn't be rebuilt
7581 // so the timetable would validate and load and the name would appear in the dropdown list. The reason was that ContinuationNameMap was only built in TryToLinkTrack,
7582 // so if that isn't called (as it isn't for a name change) then the error wouldn't be seen. However next time the railway was loaded TryToLinkTrack was called
7583 // so the error would be seen.
7584 // This inclusion rebuilds ContinuationNameMap whenever a name is entered or changed so the error can no longer be hidden.
7585  std::pair<AnsiString, char>TempMapPair;
7586 
7587  ContinuationNameMap.clear();
7588  for(int x = 0; x < Track->TrackVectorSize(); x++)
7589  {
7590  if((Track->TrackVector.at(x).TrackType == Continuation) && (Track->TrackVector.at(x).ActiveTrackElementName != ""))
7591  {
7592  TempMapPair.first = Track->TrackVector.at(x).ActiveTrackElementName;
7593  TempMapPair.second = 'x'; // unused
7594  ContinuationNameMap.insert(TempMapPair);
7595  }
7596  }
7597 //end of addition
7598  CheckLocationNameMultiMap(1); // test
7599  Utilities->CallLogPop(562);
7600 }
7601 
7602 // ---------------------------------------------------------------------------
7603 
7604 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
7605 /*
7606  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
7607  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
7608 */
7609 {
7610  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7611  AnsiString(SpeedTag));
7612  if(!NamedLocationElementAt(2, HLoc, VLoc))
7613  {
7614  Utilities->CallLogPop(948);
7615  return false;
7616  }
7617  bool FoundFlag;
7618  int Position = -1;
7619  TIMPair IMPair;
7620 
7621  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
7622  {
7623  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
7624  if(FoundFlag)
7625  {
7626  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
7627  {
7628  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
7629  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
7630  // don't allow duplicates in either list, or processing takes a lot longer
7631  {
7632  FoundElement = MapPos;
7633  Utilities->CallLogPop(563);
7634  return true;
7635  }
7636  }
7637  }
7638  }
7639  else
7640  {
7641  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
7642  if(FoundFlag)
7643  {
7644  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
7645  {
7646  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
7647  {
7648  FoundElement = IMPair.first;
7649  Utilities->CallLogPop(564);
7650  return true;
7651  }
7652  }
7653  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
7654  {
7655  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
7656  {
7657  FoundElement = IMPair.second;
7658  Utilities->CallLogPop(565);
7659  return true;
7660  }
7661  }
7662  }
7663  }
7664  Utilities->CallLogPop(566);
7665  return false;
7666 }
7667 
7668 // ---------------------------------------------------------------------------
7669 
7670 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
7671 /*
7672  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
7673  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
7674  with the new name
7675 */
7676 {
7677  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
7678  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
7679 
7680  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
7681  int HLoc = TrackElement->HLoc;
7682  int VLoc = TrackElement->VLoc;
7683  bool FoundFlag;
7684 
7685  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
7686  // only have timetable names for adjacent platforms & named locations
7687  {
7688  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
7689  if(FoundFlag)
7690  {
7691  TrackElementAt(23, Position).ActiveTrackElementName = Name;
7692  }
7693  }
7694  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
7695 
7696  if(ErrorString != "")
7697  {
7698  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
7699  }
7700  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
7701  CheckLocationNameMultiMap(2); // test
7702  Utilities->CallLogPop(567);
7703 }
7704 
7705 // ---------------------------------------------------------------------------
7706 
7707 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
7708 /*
7709  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
7710 */
7711 {
7712  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
7713  if(LNDone2MultiMap.empty())
7714  {
7715  Utilities->CallLogPop(568);
7716  return false;
7717  }
7718  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
7719 
7720  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
7721  {
7722  if(LNDone2MultiMapIterator->second == MapPos)
7723  {
7724  Utilities->CallLogPop(569);
7725  return true;
7726  }
7727  }
7728  Utilities->CallLogPop(570);
7729  return false;
7730 }
7731 
7732 // ---------------------------------------------------------------------------
7733 
7734 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
7735 /*
7736  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
7737 */
7738 {
7739  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
7740  if(LNPendingList.empty())
7741  {
7742  Utilities->CallLogPop(571);
7743  return false;
7744  }
7745  TLNPendingListIterator LNPendingListIterator;
7746 
7747  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
7748  {
7749  if(*LNPendingListIterator == MapPos)
7750  {
7751  Utilities->CallLogPop(572);
7752  return true;
7753  }
7754  }
7755  Utilities->CallLogPop(573);
7756  return false;
7757 }
7758 
7759 // ---------------------------------------------------------------------------
7760 
7761 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
7762 /*
7763  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
7764 */
7765 {
7766  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7767  THVPair HVPair(HLoc, VLoc);
7768  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
7769  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
7770 
7771  if(TrackMapPtr != TrackMap.end()) // =end() if not found
7772  {
7773  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
7774  {
7775  Utilities->CallLogPop(574);
7776  return true;
7777  }
7778  }
7779  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
7780  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
7781  {
7782  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
7783  {
7784  Utilities->CallLogPop(575);
7785  return true;
7786  }
7787  }
7788  Utilities->CallLogPop(576);
7789  return false;
7790 }
7791 
7792 // ---------------------------------------------------------------------------
7793 
7794 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
7795 {
7796  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
7797  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
7798  {
7799  Utilities->CallLogPop(1953);
7800  return true;
7801  }
7802  Utilities->CallLogPop(1954);
7803  return false;
7804 }
7805 
7806 // ---------------------------------------------------------------------------
7807 
7808 bool TTrack::DuplicatedLocationName(int Caller, bool GiveMessage)
7809 //examines LocationNameMultiMap and returns true if there are two or more locations with the same name - added at v2.6.1 to cater for Bill78's new .dev file merge
7810 //program and used when try to save as a .rly file
7811 {
7812  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DuplicatedLocationName");
7815  if(LocationNameMultiMap.empty()) //no names so no duplicates
7816  {
7817  Utilities->CallLogPop(2254);
7818  return false;
7819  }
7820  AnsiString NameBeingChecked = LocationNameMultiMap.begin()->first; //first name to start with
7821  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked);
7822  if(NameBeingChecked != "") //added for v2.6.2 as 2.6.1 reported duplicate null names (reported by Micke(Commuterpop) 06/01/21 via discord)
7823  {
7825  {
7826  if(GiveMessage)
7827  {
7828  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
7829  }
7830  Utilities->CallLogPop(2255);
7831  return true;
7832  }
7833  }
7834  while(LNMMRg.second != LocationNameMultiMap.end()) //here LNMMRg still set to earlier name
7835  {
7836  NameBeingChecked = LNMMRg.second->first; //this is the next name as LNMMRg->second points to the first location NOT containing the first name
7837  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked); //here LNMMRg is the new range
7838  if(NameBeingChecked != "") //should have skipped all null names as all listed together but add to be on the safe side
7839  {
7841  {
7842  if(GiveMessage)
7843  {
7844  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
7845  }
7846  Utilities->CallLogPop(2256);
7847  return true;
7848  }
7849  }
7850  }
7851  Utilities->CallLogPop(2257);
7852  return false; //OK, no duplicates
7853 }
7854 
7855 // ---------------------------------------------------------------------------
7856 
7858 {
7859  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateHVPairsLinkedMapAndNoDuplicates");
7860  THVPair HVPair;
7861  THVPairsLinkedMap HVPairsLinkedMap; //this is a map of HVPairs (so each is unique), each with a boolean marker, false for not linked and true for linked
7862  //for use in the duplicate check
7863  for(TLocationNameMultiMapIterator LNMMIt = LNMMRg.first; LNMMIt != LNMMRg.second; LNMMIt++) //populating the linked map
7864  {
7865  if(LNMMIt->second < 0) //active track element
7866  {
7867  HVPair.first = TrackElementAt(1011, (-1 - LNMMIt->second)).HLoc;
7868  HVPair.second = TrackElementAt(1012, (-1 - LNMMIt->second)).VLoc;
7869  }
7870  else //inactive track element
7871  {
7872  HVPair.first = InactiveTrackElementAt(134, LNMMIt->second).HLoc;
7873  HVPair.second = InactiveTrackElementAt(135, LNMMIt->second).VLoc;
7874  }
7875  HVPairsLinkedMap.insert(std::pair<THVPair, bool>(HVPair, false)); //set all bools to false initially
7876  }
7877  //All HVPairs now present in HVPairsLinkedMap for the specific location name
7878 
7879  //now need to identify all named elements that are linked either vertically or horizontally with the first one (could be any but must be just one)
7880  //so that at the end any that haven't been identified aren't linked and so represent a duplicated name
7881  //to do so need a list (works like LNPendingList) to hold all elements that haven't been checked for links
7882 
7883  std::list<THVPair> HVLinkedList;
7884 
7885  //set the first value to true and add it to the list
7886  HVPairsLinkedMap.begin()->second = true;
7887  HVLinkedList.push_back(HVPairsLinkedMap.begin()->first);
7888  //now enter a loop to examine the front pair in the list and set all linked bools to true, and if they weren't already true then add them to the back of the list for later
7889  //examination
7890  THVPair HVPairUnderExamination;
7891  THVPairsLinkedMap::iterator HVPLMIt;
7892  THVPair HVPairNew;
7893  while(!HVLinkedList.empty())
7894  {
7895  HVPairUnderExamination = HVLinkedList.front();
7896  HVLinkedList.pop_front();
7897  HVPairNew.first = HVPairUnderExamination.first;
7898  HVPairNew.second = HVPairUnderExamination.second - 1; //position directly above element
7899  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
7900  if(HVPLMIt != HVPairsLinkedMap.end())
7901  {
7902  if(!HVPLMIt->second)
7903  {
7904  HVLinkedList.push_back(HVPLMIt->first);
7905  }
7906  HVPLMIt->second = true;
7907  }
7908  HVPairNew.first = HVPairUnderExamination.first - 1;
7909  HVPairNew.second = HVPairUnderExamination.second; //position to the left of the element
7910  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
7911  if(HVPLMIt != HVPairsLinkedMap.end())
7912  {
7913  if(!HVPLMIt->second)
7914  {
7915  HVLinkedList.push_back(HVPLMIt->first);
7916  }
7917  HVPLMIt->second = true;
7918  }
7919  HVPairNew.first = HVPairUnderExamination.first;
7920  HVPairNew.second = HVPairUnderExamination.second + 1; //position under the element
7921  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
7922  if(HVPLMIt != HVPairsLinkedMap.end())
7923  {
7924  if(!HVPLMIt->second)
7925  {
7926  HVLinkedList.push_back(HVPLMIt->first);
7927  }
7928  HVPLMIt->second = true;
7929  }
7930  HVPairNew.first = HVPairUnderExamination.first + 1;
7931  HVPairNew.second = HVPairUnderExamination.second; //position to the right of the element
7932  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
7933  if(HVPLMIt != HVPairsLinkedMap.end())
7934  {
7935  if(!HVPLMIt->second)
7936  {
7937  HVLinkedList.push_back(HVPLMIt->first);
7938  }
7939  HVPLMIt->second = true;
7940  }
7941  }
7942 
7943  //at the end if any have a false bool then the name is duplicated so return false
7944  for(THVPairsLinkedMap::iterator HVPLMIt = HVPairsLinkedMap.begin(); HVPLMIt != HVPairsLinkedMap.end(); HVPLMIt++)
7945  {
7946  if(!HVPLMIt->second)
7947  {
7948  Utilities->CallLogPop(2258);
7949  return false;
7950  }
7951  }
7952  Utilities->CallLogPop(2259);
7953  return true;
7954 }
7955 
7956 // ---------------------------------------------------------------------------
7957 
7958 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
7959 /*
7960  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
7961 */
7962 
7963 {
7964  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
7965  if(LocationName == "")
7966  {
7967  Utilities->CallLogPop(577);
7968  return false;
7969  }
7970 // new for v0.2b
7971 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
7973  {
7974  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
7975  ActiveTrackElementNameMap.clear();
7976  for(unsigned int x = 0; x < TrackVector.size(); x++)
7977  {
7978  if((TrackVector.at(x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackVector.at(x).ActiveTrackElementName))
7979  == ContinuationNameMap.end())
7980  { // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
7981  ActiveTrackElementNameMapEntry.first = Track->TrackVector.at(x).ActiveTrackElementName;
7982  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
7983  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
7984  }
7985  }
7987  }
7988  Utilities->CallLogPop(578);
7989  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
7990 // end of new section
7991 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
7992 }
7993 
7994 // ---------------------------------------------------------------------------
7995 
7996 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
7997 /*
7998  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
7999  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
8000  new names in the vectors.
8001 */
8002 {
8003  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
8004  bool FoundFlag, ErasedFlag = false;
8005  TLocationNameMultiMapIterator SNIterator;
8006  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8007 
8008  if(SNRange.first != SNRange.second)
8009  {
8010  ErasedFlag = true;
8011  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
8012  {
8013  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
8014  TVIt->LocationName = "";
8015  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8016  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
8017  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8018  {
8019  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8020  if(FoundFlag)
8021  {
8022  TrackElementAt(25, Position).LocationName = "";
8023  TrackElementAt(26, Position).ActiveTrackElementName = "";
8024  }
8025  }
8026  }
8027  }
8028  if(ErasedFlag)
8030  CheckLocationNameMultiMap(3); // test
8031  Utilities->CallLogPop(579);
8032 }
8033 
8034 // ---------------------------------------------------------------------------
8035 
8036 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
8037 /*
8038  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
8039  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
8040  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
8041  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during EraseTrackElement (in which
8042  case the SpeedTag is that for the element that is erased) and PlotAndAddTrackElement, to bring the named location and timetable
8043  naming up to date with the deletion or insertion.
8044 */
8045 {
8046  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
8047  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
8048  LNPendingList.clear();
8049  AnsiString LocationName;
8050  int MapPos;
8051  bool FoundFlag = 0;
8052 
8053 //first check if this element is inactive and named, and if so use its position and name (new at v2.6.0 to allow pasted named locations to name linked elements)
8054  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(30, HLoc, VLoc, FoundFlag);
8055  if(FoundFlag)
8056  {
8057  LocationName = InactiveTrackElementAt(132, IMPair.first).LocationName;
8058  if(LocationName != "")
8059  {
8060  LNPendingList.insert(Track->LNPendingList.end(), IMPair.first);
8061  EnterLocationName(13, LocationName, true);
8062  Utilities->CallLogPop(2251);
8063  return;
8064  }
8065  LocationName = InactiveTrackElementAt(133, IMPair.second).LocationName;
8066  if(LocationName != "")
8067  {
8068  LNPendingList.insert(Track->LNPendingList.end(), IMPair.second);
8069  EnterLocationName(14, LocationName, true);
8070  Utilities->CallLogPop(2252);
8071  return;
8072  }
8073  }
8074 //then check if this element is active and named, and if so use its position (-Pos-1) and name (new at v2.6.0 to allow pasted named locations to name linked elements)
8075 
8076  int Position = GetVectorPositionFromTrackMap(59, HLoc, VLoc, FoundFlag);
8077  if(FoundFlag)
8078  {
8079  LocationName = TrackElementAt(1004, Position).LocationName;
8080  if(LocationName != "")
8081  {
8082  int ModifiedPosition = -1 - Position;
8083  LNPendingList.insert(Track->LNPendingList.end(), ModifiedPosition);
8084  EnterLocationName(15, LocationName, true);
8085  Utilities->CallLogPop(2253);
8086  return;
8087  }
8088  }
8089 
8090  if(SpeedTag == 76) // top plat
8091  {
8092  for(int x = 0; x < 25; x++)
8093  {
8094  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
8095  {
8096  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8097  EnterLocationName(3, LocationName, true);
8098  break;
8099  }
8100  }
8101  }
8102  else if(SpeedTag == 77) // bot plat
8103  {
8104  for(int x = 0; x < 25; x++)
8105  {
8106  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
8107  {
8108  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8109  EnterLocationName(4, LocationName, true);
8110  break;
8111  }
8112  }
8113  }
8114  else if(SpeedTag == 78) // l plat
8115  {
8116  for(int x = 0; x < 25; x++)
8117  {
8118  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
8119  {
8120  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8121  EnterLocationName(5, LocationName, true);
8122  break;
8123  }
8124  }
8125  }
8126  else if(SpeedTag == 79) // r plat
8127  {
8128  for(int x = 0; x < 25; x++)
8129  {
8130  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
8131  {
8132  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8133  EnterLocationName(6, LocationName, true);
8134  break;
8135  }
8136  }
8137  }
8138  else if(SpeedTag == 96) // conc
8139  {
8140  for(int x = 0; x < 28; x++)
8141  {
8142  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
8143  {
8144  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8145  EnterLocationName(7, LocationName, true);
8146  break;
8147  }
8148  }
8149  }
8150  else if(SpeedTag == 129) // vert footbridge
8151  {
8152  for(int x = 0; x < 8; x++)
8153  {
8154  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
8155  {
8156  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8157  EnterLocationName(8, LocationName, true);
8158  break;
8159  }
8160  }
8161  }
8162  else if(SpeedTag == 130) // hor footbridge
8163  {
8164  for(int x = 0; x < 8; x++)
8165  {
8166  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
8167  {
8168  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8169  EnterLocationName(9, LocationName, true);
8170  break;
8171  }
8172  }
8173  }
8174  else if(SpeedTag == 145) // vert u'pass
8175  {
8176  for(int x = 0; x < 8; x++)
8177  {
8178  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
8179  {
8180  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8181  EnterLocationName(11, LocationName, true);
8182  break;
8183  }
8184  }
8185  }
8186  else if(SpeedTag == 146) // hor u'pass
8187  {
8188  for(int x = 0; x < 8; x++)
8189  {
8190  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
8191  {
8192  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8193  EnterLocationName(12, LocationName, true);
8194  break;
8195  }
8196  }
8197  }
8198  else if(SpeedTag == 131) // named location
8199  {
8200  for(int x = 0; x < 4; x++)
8201  {
8202  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
8203  {
8204  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8205  EnterLocationName(10, LocationName, true);
8206  break;
8207  }
8208  }
8209  }
8210 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
8211  Utilities->CallLogPop(580);
8212 }
8213 
8214 // ---------------------------------------------------------------------------
8215 
8216 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
8217 /*
8218  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
8219  true if a LocationName is found, and also returns the name and the adjusted vector position.
8220 */
8221 {
8222  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8223  AnsiString(SpeedTag));
8224  bool FoundFlag;
8225  TIMPair IMPair;
8226  TTrackVectorIterator TempElement;
8227  int Position;
8228 
8229  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
8230  if(FoundFlag)
8231  {
8232  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
8233  {
8234  TempElement = InactiveTrackVector.begin() + IMPair.first;
8235  if(TempElement->LocationName != "")
8236  {
8237  LocationName = TempElement->LocationName;
8238  FoundElement = IMPair.first;
8239  Utilities->CallLogPop(581);
8240  return true;
8241  }
8242  }
8243  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
8244  {
8245  TempElement = InactiveTrackVector.begin() + IMPair.second;
8246  if(TempElement->LocationName != "")
8247  {
8248  LocationName = TempElement->LocationName;
8249  FoundElement = IMPair.second;
8250  Utilities->CallLogPop(582);
8251  return true;
8252  }
8253  }
8254  }
8255 
8256  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
8257  if(FoundFlag)
8258  {
8259  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
8260  {
8261  TempElement = TrackVector.begin() + Position;
8262  if(TempElement->LocationName != "")
8263  {
8264  LocationName = TempElement->LocationName;
8265  FoundElement = -1 - Position;
8266  Utilities->CallLogPop(583);
8267  return true;
8268  }
8269  }
8270  }
8271  Utilities->CallLogPop(584);
8272  return false;
8273 }
8274 
8275 // ---------------------------------------------------------------------------
8276 
8277 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
8278 {
8279 // check quantity in map & vectors match
8280  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
8281  unsigned int Count = 0;
8282 
8283  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
8284  {
8285  Utilities->CallLogPop(2059);
8286  return;
8287  }
8288 
8289  AnsiString SName, TName, ErrorString;
8290 
8291  for(unsigned int x = 0; x < TrackVector.size(); x++)
8292  {
8293  if(TrackVector.at(x).FixedNamedLocationElement)
8294  {
8295  if(TrackVector.at(x).TrackType != FootCrossing)
8296  {
8297  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
8298  AnsiString(Caller));
8299  }
8300  Count++;
8301  }
8302  }
8303  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
8304  {
8305  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
8306  {
8307  if((InactiveTrackVector.at(x).TrackType != Platform) && (InactiveTrackVector.at(x).TrackType != NamedNonStationLocation) &&
8308  (InactiveTrackVector.at(x).TrackType != Concourse))
8309  {
8310  throw Exception
8311  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
8312  AnsiString(Caller));
8313  }
8314  Count++;
8315  }
8316  }
8317  if(LocationNameMultiMap.size() != Count)
8318  {
8319  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
8320  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
8321  }
8322 
8323 // check all entries in both vectors match entries in name multimap
8325 
8326  for(unsigned int x = 0; x < TrackVector.size(); x++)
8327  {
8328  if(TrackVector.at(x).FixedNamedLocationElement)
8329  {
8330  SName = TrackVector.at(x).LocationName;
8331  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
8332  if(ErrorString != "")
8333  {
8334  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
8335  }
8336  if(SNIt->second != -1 - (int)x)
8337  {
8338  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
8339  AnsiString(Caller));
8340  }
8341  }
8342  // check corresponding platform for all Timetable entries that aren't empty
8343  TName = TrackVector.at(x).ActiveTrackElementName;
8344  TIMPair IMPair;
8345  bool FoundFlag = false;
8346  if(TName != "")
8347  {
8348  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc, FoundFlag);
8349  if(FoundFlag)
8350  {
8351  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
8353  {
8354  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackVector.at(x).HLoc) + " & V " +
8355  AnsiString(TrackVector.at(x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
8356  }
8357  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
8358  {
8359  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackVector.at(x).HLoc) +
8360  " & V " + AnsiString(TrackVector.at(x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
8361  AnsiString(Caller));
8362  }
8363  }
8364  else
8365  {
8366  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackVector.at(x).HLoc) + " & V " +
8367  AnsiString(TrackVector.at(x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
8368  }
8369  }
8370  }
8371  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
8372  {
8373  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
8374  {
8375  SName = InactiveTrackVector.at(x).LocationName;
8376  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
8377  if(ErrorString != "")
8378  {
8379  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
8380  }
8381  if(SNIt->second != (int)x)
8382  {
8383  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
8384  AnsiString(Caller));
8385  }
8386  }
8387  }
8388  Utilities->CallLogPop(585);
8389 }
8390 
8391 // ---------------------------------------------------------------------------
8392 
8394  AnsiString &ErrorString)
8395 {
8396 /*
8397  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
8398  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
8399  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
8400 */
8401  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
8402  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
8403  ErrorString = "";
8404  bool FoundFlag = false;
8405  TLocationNameMultiMapIterator SNIterator;
8406  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8407 
8408  if(SNRange.first == SNRange.second)
8409  {
8410  ErrorString = "Error, Name " + LocationName + " not found in map";
8411  Utilities->CallLogPop(586);
8412  return SNRange.first;
8413  }
8414  else
8415  {
8416  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
8417  {
8418  if(SNIterator->second < 0)
8419  {
8420  int TVPos = -1 - SNIterator->second;
8421  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
8422  if(TVIt == TrackElement)
8423  {
8424  FoundFlag = true;
8425  Utilities->CallLogPop(587);
8426  return SNIterator;
8427  }
8428  }
8429  else
8430  {
8431  int ITVPos = SNIterator->second;
8432  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
8433  if(ITVIt == TrackElement)
8434  {
8435  FoundFlag = true;
8436  Utilities->CallLogPop(588);
8437  return SNIterator;
8438  }
8439  }
8440  }
8441  }
8442  if(!FoundFlag)
8443  ErrorString = "Error, Name " + LocationName + " found but not at required element";
8444  Utilities->CallLogPop(589);
8445  return SNIterator;
8446 }
8447 
8448 // ---------------------------------------------------------------------------
8449 
8450 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
8451 {
8452 /*
8453  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
8454  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
8455 */
8456  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
8457  TLocationNameMultiMapEntry LocationNameEntry;
8458 
8459  LocationNameEntry.first = NewName;
8460  LocationNameEntry.second = SNIterator->second;
8461  LocationNameMultiMap.erase(SNIterator);
8462  LocationNameMultiMap.insert(LocationNameEntry);
8463  Utilities->CallLogPop(590);
8464 }
8465 
8466 // ---------------------------------------------------------------------------
8467 
8469 {
8470 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
8471  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
8472  if(Position < 0) // footcrossing
8473  {
8474  int TruePos = -1 - Position;
8475  // new check at v0.2b
8476  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
8477  {
8478  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
8479  }
8480  Utilities->CallLogPop(591);
8481  return (TrackVector.begin() + TruePos);
8482  }
8483  else
8484  {
8485  // new check at v0.2b
8486  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
8487  {
8488  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
8489  }
8490  Utilities->CallLogPop(592);
8491  return (InactiveTrackVector.begin() + Position);
8492  }
8493 }
8494 
8495 // ---------------------------------------------------------------------------
8496 
8497 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
8498 {
8499 /*
8500  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
8501  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
8502  LocationNameMultiMap.
8503 */
8504  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
8505  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
8506  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
8507 
8508  if(!InactiveTrack2MultiMap.empty())
8509  {
8510  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
8511  InactiveTrack2MultiMapIterator++)
8512  {
8513  if(InactiveTrack2MultiMapIterator->second > VecPos)
8514  InactiveTrack2MultiMapIterator->second--;
8515  // can't be == VecPos as that position erased
8516  }
8517  }
8518  if(!LocationNameMultiMap.empty())
8519  {
8520  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
8521  LocationNameMultiMapIterator++)
8522  {
8523  if(LocationNameMultiMapIterator->second < 0)
8524  continue; // deal with TrackVectors separately
8525  if(LocationNameMultiMapIterator->second > (int)VecPos)
8526  LocationNameMultiMapIterator->second--;
8527  }
8528  }
8529  Utilities->CallLogPop(593);
8530 }
8531 
8532 // ---------------------------------------------------------------------------
8533 
8534 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
8535 {
8536 /*
8537  After an element has been erased from the track vector, all the later elements are moved down one. This function
8538  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
8539  LocationNameMultiMap.
8540 */
8541  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
8542  TTrackMapIterator TrackMapIterator;
8543  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
8544 
8545  if(!TrackMap.empty())
8546  {
8547  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
8548  {
8549  if(TrackMapIterator->second > VecPos)
8550  TrackMapIterator->second--;
8551  // can't be == VecPos as that position erased
8552  }
8553  }
8554  if(!LocationNameMultiMap.empty())
8555  {
8556  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
8557  LocationNameMultiMapIterator++)
8558  {
8559  if(LocationNameMultiMapIterator->second >= 0)
8560  continue; // deal with InactiveTrackVectors separately
8561  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
8562  // Val -1 -2 -3 -4 -5 -6 -7 -8
8563  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
8564  LocationNameMultiMapIterator->second++;
8565  }
8566  }
8567  for(unsigned int x = 0; x < TrackVector.size(); x++)
8568  {
8569  TTrackElement &TkEl = TrackVector.at(x); // no need to check so use this to speed up
8570  if(TkEl.TrackType == GapJump)
8571  {
8572  // position 0 is the gap
8573  if(TkEl.Conn[0] == int(VecPos))
8574  {
8575  TkEl.Conn[0] = -1; // connected to a deleted gap
8576  continue;
8577  }
8578  if(TkEl.Conn[0] > int(VecPos))
8579  TkEl.Conn[0]--;
8580  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
8581  {
8582  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
8583  TkEl.Conn[0] = -1;
8584  }
8585  }
8586  }
8587  Utilities->CallLogPop(1433);
8588 }
8589 
8590 // ---------------------------------------------------------------------------
8591 
8593 /*
8594  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
8595  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
8596  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
8597 */
8598 {
8599  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
8600  LocationNameMultiMap.clear();
8601  TLocationNameMultiMapEntry LocationNameEntry;
8602  TTrackElement TrackElement;
8603 
8604  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
8605  {
8606  TrackElement = TrackVector.at(TVPos);
8607  if(TrackElement.FixedNamedLocationElement)
8608  {
8609  LocationNameEntry.first = TrackElement.LocationName;
8610  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
8611  LocationNameMultiMap.insert(LocationNameEntry);
8612  }
8613  }
8614 
8615  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
8616  {
8617  TrackElement = InactiveTrackVector.at(ITVPos);
8618  if(TrackElement.FixedNamedLocationElement)
8619  {
8620  LocationNameEntry.first = TrackElement.LocationName;
8621  LocationNameEntry.second = ITVPos;
8622  LocationNameMultiMap.insert(LocationNameEntry);
8623  }
8624  }
8625  Utilities->CallLogPop(594);
8626 }
8627 
8628 // ---------------------------------------------------------------------------
8629 
8631  // Return true if there is a named location present in the railway
8632  // ignores lone footcrossings, can't name these on their own & track won't link if there are any
8633 {
8634  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
8635  TTrackVectorIterator ITVI;
8636 
8637  if(InactiveTrackVector.empty())
8638  {
8639  Utilities->CallLogPop(1343);
8640  return false;
8641  }
8642  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
8643  {
8644  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
8645  {
8646  Utilities->CallLogPop(1404);
8647  return true;
8648  }
8649  }
8650  Utilities->CallLogPop(1344);
8651  return false;
8652 }
8653 
8654 // ---------------------------------------------------------------------------
8655 
8657 /*
8658  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
8659 */
8660 {
8661  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
8662 // ResetDistanceElements(6);
8663  for(unsigned int x = 0; x < TrackVector.size(); x++)
8664  {
8665  TTrackElement &TE = TrackElementAt(718, x);
8668  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
8669  {
8672  }
8673  }
8674 /* old function
8675  if((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == Crossover) || (TrackVector.at(x).TrackType == Bridge))
8676  {
8677  SetOneDefaultTrackLength(2, TrackVector.at(x), 0);
8678  SetOneDefaultTrackLength(3, TrackVector.at(x), 2);
8679  }
8680  else
8681  {
8682  SetOneDefaultTrackLength(4, TrackVector.at(x), 0);
8683  }
8684  }
8685 */
8686  Utilities->CallLogPop(617);
8687 }
8688 
8689 // ---------------------------------------------------------------------------
8690 
8691 void TTrack::LengthMarker(int Caller, TDisplay *Disp)
8692  // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLength.
8693 {
8694  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthMarker");
8695  for(unsigned int x = 0; x < TrackVector.size(); x++)
8696  {
8697  TTrackElement TempElement = TrackVector.at(x);
8698  if(TempElement.Length01 > -1)
8699  MarkOneLength(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
8700  if(TempElement.Length23 > -1)
8701  MarkOneLength(2, TempElement, false, Disp);
8702  }
8703  Disp->Update();
8704  Utilities->CallLogPop(618);
8705 }
8706 
8707 // ---------------------------------------------------------------------------
8708 
8709 void TTrack::MarkOneLength(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
8710 /*
8711  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h
8712  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
8713  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
8714  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
8715  track as indicated by FirstTrack (true for track01 & false for track23).
8716 */
8717 {
8718  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLength," + TrackElement.LogTrack(8) + "," +
8719  AnsiString((short)FirstTrack));
8720  bool LengthDifferent = false, SpeedDifferent = false;
8721 
8722  if(IsElementDefaultLength(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
8723  {
8724  Utilities->CallLogPop(619);
8725  return;
8726  }
8727 
8728  int EXArray[16][2] =
8729  {{4, 6}, {2, 8}, // horizontal & vertical
8730  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
8731  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
8732  {1, 9}, {3, 7}}; // forward & reverse diagonals
8733 
8734  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
8735  Graphics::TBitmap *Bitmap;
8736 
8737  if(FirstTrack)
8738  {
8739  InLink = TrackElement.Link[0];
8740  OutLink = TrackElement.Link[1];
8741  }
8742  else
8743  {
8744  InLink = TrackElement.Link[2];
8745  OutLink = TrackElement.Link[3];
8746  }
8747 
8748  for(int x = 0; x < 16; x++)
8749  {
8750  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
8751  Index = x;
8752  }
8753  if(Index == -1)
8754  {
8755  throw Exception("Error, failed to find Index in TTrack::MarkOneLength");
8756  }
8757 
8758 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
8759  the graphic for each of which is different because of the shape of the overbridge. The basic
8760  entry/exit value is computed above, and this used to select only from elements with that entry/exit
8761  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
8762  int BrEXArray[24][2] = {
8763  {4,6},{2,8},{1,9},{3,7},
8764  {1,9},{3,7},{1,9},{3,7},
8765  {2,8},{4,6},{2,8},{4,6}
8766 */
8767  if(!FirstTrack && (TrackElement.TrackType == Bridge))
8768  {
8769  if(Index == 1)
8770  {
8771  if(TrackElement.SpeedTag == 49)
8772  BrNum = 1 + 16;
8773  else if(TrackElement.SpeedTag == 54)
8774  BrNum = 8 + 16;
8775  else if(TrackElement.SpeedTag == 55)
8776  BrNum = 10 + 16;
8777  }
8778  else if(Index == 0)
8779  {
8780  if(TrackElement.SpeedTag == 48)
8781  BrNum = 0 + 16;
8782  else if(TrackElement.SpeedTag == 58)
8783  BrNum = 11 + 16;
8784  else if(TrackElement.SpeedTag == 59)
8785  BrNum = 9 + 16;
8786  }
8787  else if(Index == 14)
8788  {
8789  if(TrackElement.SpeedTag == 50)
8790  BrNum = 2 + 16;
8791  else if(TrackElement.SpeedTag == 52)
8792  BrNum = 4 + 16;
8793  else if(TrackElement.SpeedTag == 57)
8794  BrNum = 6 + 16;
8795  }
8796  else if(Index == 15)
8797  {
8798  if(TrackElement.SpeedTag == 51)
8799  BrNum = 3 + 16;
8800  else if(TrackElement.SpeedTag == 53)
8801  BrNum = 7 + 16;
8802  else if(TrackElement.SpeedTag == 56)
8803  BrNum = 5 + 16;
8804  }
8805  }
8806 
8807  if(!FirstTrack && (TrackElement.TrackType == Bridge))
8808  GrNum = BrNum;
8809  else
8810  GrNum = Index;
8811 
8812  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
8813  {
8814  if(GrNum > 15) // underbridge
8815  {
8816  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
8817  }
8818  else
8819  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
8820 
8821  if(TrackElement.SpeedTag == 64)
8822  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
8823  if(TrackElement.SpeedTag == 65)
8825  if(TrackElement.SpeedTag == 66)
8827  if(TrackElement.SpeedTag == 67)
8829 
8830  if(TrackElement.SpeedTag == 80)
8831  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
8832  if(TrackElement.SpeedTag == 81)
8834  if(TrackElement.SpeedTag == 82)
8836  if(TrackElement.SpeedTag == 83)
8838  if(TrackElement.SpeedTag == 84)
8840  if(TrackElement.SpeedTag == 85)
8842  if(TrackElement.SpeedTag == 86)
8844  if(TrackElement.SpeedTag == 87)
8846 
8847  if(TrackElement.SpeedTag == 129)
8848  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
8849  if(TrackElement.SpeedTag == 130)
8851  }
8852 
8853  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
8854  {
8855  if(GrNum > 15) // underbridge
8856  {
8857  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
8858  }
8859  else
8860  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
8861 
8862  if(TrackElement.SpeedTag == 64)
8863  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
8864  if(TrackElement.SpeedTag == 65)
8865  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
8866  if(TrackElement.SpeedTag == 66)
8867  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
8868  if(TrackElement.SpeedTag == 67)
8869  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
8870 
8871  if(TrackElement.SpeedTag == 80)
8872  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
8873  if(TrackElement.SpeedTag == 81)
8874  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
8875  if(TrackElement.SpeedTag == 82)
8876  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
8877  if(TrackElement.SpeedTag == 83)
8878  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
8879  if(TrackElement.SpeedTag == 84)
8880  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
8881  if(TrackElement.SpeedTag == 85)
8882  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
8883  if(TrackElement.SpeedTag == 86)
8884  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
8885  if(TrackElement.SpeedTag == 87)
8886  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
8887 
8888  if(TrackElement.SpeedTag == 129)
8889  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
8890  if(TrackElement.SpeedTag == 130)
8891  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
8892  }
8893 
8894  else // SpeedDifferent only: red - use non sig graphics
8895  {
8896  if(GrNum > 15) // underbridge
8897  {
8898  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
8899  }
8900  else
8901  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
8902 
8903  if(TrackElement.SpeedTag == 64)
8904  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
8905  if(TrackElement.SpeedTag == 65)
8907  if(TrackElement.SpeedTag == 66)
8909  if(TrackElement.SpeedTag == 67)
8911 
8912  if(TrackElement.SpeedTag == 80)
8913  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
8914  if(TrackElement.SpeedTag == 81)
8916  if(TrackElement.SpeedTag == 82)
8918  if(TrackElement.SpeedTag == 83)
8920  if(TrackElement.SpeedTag == 84)
8922  if(TrackElement.SpeedTag == 85)
8924  if(TrackElement.SpeedTag == 86)
8926  if(TrackElement.SpeedTag == 87)
8928 
8929  if(TrackElement.SpeedTag == 129)
8930  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
8931  if(TrackElement.SpeedTag == 130)
8933  }
8934 
8935  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
8936  Utilities->CallLogPop(620);
8937 }
8938 
8939 // ---------------------------------------------------------------------------
8940 
8941 bool TTrack::IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
8942 /* FirstTrack = LinkPos's 0 & 1
8943  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
8944 */
8945 {
8946  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementTrackDefaultLength," + TrackElement.LogTrack(10) + "," +
8947  AnsiString((short)FirstTrack));
8948  LengthDifferent = false;
8949  SpeedDifferent = false;
8950  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
8951  {
8952  if(TrackElement.Length01 != DefaultTrackLength)
8953  {
8954  LengthDifferent = true;
8955  }
8956  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
8957  {
8958  SpeedDifferent = true;
8959  }
8960  if(LengthDifferent || SpeedDifferent)
8961  {
8962  Utilities->CallLogPop(625);
8963  return false;
8964  }
8965  Utilities->CallLogPop(626);
8966  return true;
8967  }
8968 
8969  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
8970  {
8971  if(TrackElement.Length23 != DefaultTrackLength)
8972  {
8973  LengthDifferent = true;
8974  }
8975  if(TrackElement.SpeedLimit23 != DefaultTrackSpeedLimit)
8976  {
8977  SpeedDifferent = true;
8978  }
8979  if(LengthDifferent || SpeedDifferent)
8980  {
8981  Utilities->CallLogPop(627);
8982  return false;
8983  }
8984  Utilities->CallLogPop(628);
8985  return true;
8986  }
8987 
8988  else // any other 1 track element, including platforms being present
8989  {
8990  if(TrackElement.Length01 != DefaultTrackLength)
8991  {
8992  LengthDifferent = true;
8993  }
8994  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
8995  {
8996  SpeedDifferent = true;
8997  }
8998  if(LengthDifferent || SpeedDifferent)
8999  {
9000  Utilities->CallLogPop(629);
9001  return false;
9002  }
9003  Utilities->CallLogPop(630);
9004  return true;
9005  }
9006 }
9007 
9008 // ---------------------------------------------------------------------------
9009 
9010 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
9011  // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
9012 {
9013  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
9014  AnsiString(VLoc));
9015  bool FoundFlag;
9016  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
9017 
9018  if(!FoundFlag)
9019  {
9020  Utilities->CallLogPop(633);
9021  return false;
9022  }
9023  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
9024  {
9025  Utilities->CallLogPop(634);
9026  return true; // only need to check first since if second is a platform the the first must be too
9027  }
9028  else
9029  {
9030  Utilities->CallLogPop(635);
9031  return false;
9032  }
9033 }
9034 
9035 // ---------------------------------------------------------------------------
9036 
9037 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
9038  // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
9039 {
9040  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
9041  AnsiString(VLoc));
9042  bool FoundFlag;
9043  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
9044 
9045  if(!FoundFlag)
9046  {
9047  Utilities->CallLogPop(636);
9048  return false;
9049  }
9051  {
9052  Utilities->CallLogPop(637);
9053  return true; // only need to check first since only one used for NamedNonStationLocations
9054  }
9055  else
9056  {
9057  Utilities->CallLogPop(638);
9058  return false;
9059  }
9060 }
9061 
9062 // ---------------------------------------------------------------------------
9063 
9065 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
9066  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
9067  the front of train stop points for each direction.
9068  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
9069  end (unless buffers at one or both ends in which case stop points are the end elements).
9070  Note that for a single element the stop point is the element itself (formula doesn't apply).
9071  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
9072  repeating the procedure for every element. At the end all unused values are returned to -1.
9073  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
9074 */
9075 {
9076  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
9077  TTrackElement TempElement, StartElement;
9078  AnsiString TempName;
9079  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
9080  bool ForwardSet, ReverseSet;
9081 
9082  for(unsigned int x = 0; x < TrackVector.size(); x++)
9083  {
9084  TrackVector.at(x).StationEntryStopLinkPos1 = -1;
9085  TrackVector.at(x).StationEntryStopLinkPos2 = -1;
9086  }
9087  for(unsigned int x = 0; x < TrackVector.size(); x++)
9088  {
9089  ForwardSet = false;
9090  ReverseSet = false;
9091  TempElement = TrackVector.at(x);
9092  VecPos = x;
9093  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1))
9094  // 2nd condition incl so don't re-examine elements with stop links set to 5
9095  {
9096  TempName = TempElement.ActiveTrackElementName;
9097  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
9098  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
9099  // an element linked at both ends where both links are also named elements
9100  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
9101  {
9102  continue; // looking for an end element so skip this one
9103  }
9104  else // reached one end
9105  {
9106  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
9107  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
9108  // single named element linked at both ends
9109  {
9110  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
9111  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
9112  continue;
9113  }
9114  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
9115  // single named buffer element (LinkPos 1 is the non-buffer end)
9116  {
9117  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
9118  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
9119  continue;
9120  }
9121  else
9122  // Note: only interested in connection positions 0 & 1 since all named elements are single track except points,
9123  // and platforms always on straight (conns 0 & 1) section of points
9124  {
9125  for(int y = 0; y < 2; y++)
9126  {
9127  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
9128  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
9129 /* TTrackElement Temp1 = TempElement;
9130  ***********New section, compiles but not checked - does bit below need to be else if?
9131  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
9132  {
9133  //search along Dir direction until find other end, skip if Dir facing buffer end
9134  int NewDir = Dir;
9135  int NewVecPos;
9136  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
9137  {
9138  NewVecPos = Temp1.Conn[NewDir];
9139  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
9140  Temp1 = TrackElementAt(601, NewVecPos);
9141  }
9142  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
9143  {
9144  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
9145  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
9146  }
9147  }
9148  ***************
9149 */
9150  // end may be linked at both ends but only one link named, or buffer with linked element named
9151  // if a buffer then the named linkpos has to be 1
9152  // already dealt with all types of single element so at least 2 linked named element
9153  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
9154  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
9155  {
9156  StartElement = TempElement;
9157  StartVecPos = VecPos;
9158  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
9159  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
9160  EntryPos = 1 - Dir;
9161  StartEntryPos = 1 - Dir;
9162  Count = 1;
9163  // work along named elements until find the other end
9164  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(53,
9165  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
9166  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
9167  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
9168  // all stop link pos's are set to 5
9169  {
9170  VecPos = TempElement.Conn[1 - EntryPos];
9171  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
9172  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
9173  EntryPos = TempEntryPos;
9174  Count++;
9175  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
9176  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
9177  }
9178  // here when reached other end, maybe buffers, continuation or last named linked element
9179  if(TrackElementAt(57, VecPos).TrackType == Buffers)
9180  // terminal station, set end elements as stop elements
9181  {
9182  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
9183  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
9184  continue;
9185  }
9186  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
9187  // terminal station, set end elements as stop elements
9188  {
9189  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
9190  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
9191  continue;
9192  }
9193  if(IsNamedNonStationLocationPresent(1, TrackElementAt(63, StartVecPos).HLoc, TrackElementAt(64, StartVecPos).VLoc))
9194  // NonStationLocation so set end elements as stop elements
9195  {
9196  TrackElementAt(65, VecPos).StationEntryStopLinkPos1 = EntryPos;
9197  TrackElementAt(66, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
9198  continue;
9199  }
9200  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
9201  ForwardNumber = ((Count + 1) / 2) + 1;
9202  ReverseNumber = (Count - ForwardNumber) + 1;
9203  Count = 1; // starting value
9204  EntryPos = 1 - Dir;
9205  TempElement = StartElement;
9206  VecPos = StartVecPos;
9207  if(Count == ForwardNumber)
9208  {
9209  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
9210  ForwardSet = true;
9211  }
9212  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
9213  {
9214  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
9215  ReverseSet = true;
9216  }
9217  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
9218  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
9219  {
9220  VecPos = TempElement.Conn[1 - EntryPos];
9221  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
9222  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
9223  EntryPos = TempEntryPos;
9224  Count++;
9225  if(Count == ForwardNumber)
9226  {
9227  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
9228  ForwardSet = true;
9229  }
9230  if(Count == ReverseNumber)
9231  {
9232  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
9233  ReverseSet = true;
9234  }
9235  }
9236  }
9237  }
9238  }
9239  }
9240  }
9241  }
9242  for(unsigned int x = 0; x < TrackVector.size(); x++)
9243  {
9244  if(TrackVector.at(x).StationEntryStopLinkPos1 == 5)
9245  {
9246  TrackVector.at(x).StationEntryStopLinkPos1 = -1;
9247  }
9248  if(TrackVector.at(x).StationEntryStopLinkPos2 == 5)
9249  {
9250  TrackVector.at(x).StationEntryStopLinkPos2 = -1;
9251  }
9252  }
9253  Utilities->CallLogPop(639);
9254 }
9255 
9256 // ---------------------------------------------------------------------------
9257 
9258 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
9259 {
9260  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
9261  TTrackElement Next;
9262 
9264  while(ReturnNextInactiveTrackElement(1, Next))
9265  {
9266  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
9267  {
9268  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
9269  // need striped graphics
9270  {
9271  if(Next.SpeedTag == 76)
9272  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
9273  else if(Next.SpeedTag == 77)
9274  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
9275  else if(Next.SpeedTag == 78)
9276  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
9277  else if(Next.SpeedTag == 79)
9278  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
9279  else if(Next.SpeedTag == 96)
9280  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
9281  else if(Next.SpeedTag == 131)
9282  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
9283  }
9284  else
9285  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
9286  }
9287  }
9288 
9289  NextTrackElementPtr = TrackVector.begin();
9290  while(ReturnNextTrackElement(1, Next))
9291  {
9292  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
9293  {
9294  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
9295  {
9296  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
9297  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
9298  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
9299  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
9300  }
9301  else
9302  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
9303  }
9304  }
9305  Disp->Update();
9306  Utilities->CallLogPop(640);
9307 }
9308 
9309 // ---------------------------------------------------------------------------
9310 
9311 void TTrack::PlotSmallRedGap(int Caller)
9312 {
9313  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
9315  Utilities->CallLogPop(1346);
9316 }
9317 
9318 // ---------------------------------------------------------------------------
9319 
9320 void TTrack::TrackClear(int Caller)
9321 {
9322  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
9323  TrackVector.clear();
9324  InactiveTrackVector.clear();
9325  TrackMap.clear();
9327  if(TextHandler->TextVector.size() == 0)
9328  {
9329  Display->DisplayOffsetH = 0;
9330  Display->DisplayOffsetV = 0;
9337  HLocMin = 2000000000;
9338  HLocMax = -2000000000;
9339  VLocMin = 2000000000;
9340  VLocMax = -2000000000;
9341  }
9342  else
9343  CalcHLocMinEtc(4);
9344  Utilities->CallLogPop(1347);
9345 }
9346 
9347 // ---------------------------------------------------------------------------
9348 
9349 void TTrack::CalcHLocMinEtc(int Caller)
9350 {
9351  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
9352  HLocMin = 2000000000;
9353  VLocMin = 2000000000;
9354  HLocMax = -2000000000;
9355  VLocMax = -2000000000;
9356  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
9357  {
9358  if(TrackVector.at(x).SpeedTag == 0)
9359  continue; // skip erase elements or would interfere with Min & Max values
9360  if(TrackVector.at(x).HLoc - 1 < HLocMin)
9361  HLocMin = TrackVector.at(x).HLoc - 1; // add one all round
9362  if(TrackVector.at(x).HLoc + 1 > HLocMax)
9363  HLocMax = TrackVector.at(x).HLoc + 1;
9364  if(TrackVector.at(x).VLoc - 1 < VLocMin)
9365  VLocMin = TrackVector.at(x).VLoc - 1;
9366  if(TrackVector.at(x).VLoc + 1 > VLocMax)
9367  VLocMax = TrackVector.at(x).VLoc + 1;
9368  }
9369  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
9370  {
9371  if(InactiveTrackVector.at(x).SpeedTag == 0)
9372  continue; // shouldn't be any inactive erase elements but include anyway
9373  if(InactiveTrackVector.at(x).HLoc - 1 < HLocMin)
9374  HLocMin = InactiveTrackVector.at(x).HLoc - 1; // add one all round
9375  if(InactiveTrackVector.at(x).HLoc + 1 > HLocMax)
9376  HLocMax = InactiveTrackVector.at(x).HLoc + 1;
9377  if(InactiveTrackVector.at(x).VLoc - 1 < VLocMin)
9378  VLocMin = InactiveTrackVector.at(x).VLoc - 1;
9379  if(InactiveTrackVector.at(x).VLoc + 1 > VLocMax)
9380  VLocMax = InactiveTrackVector.at(x).VLoc + 1;
9381  }
9382  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
9383  {
9384 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
9385  will fail as x will exceed the maximum value
9386  if(TextHandler->TextPtrAt(, x)->TextString == "")
9387  {
9388  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
9389  }
9390 */
9391  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
9392  if((TextH / 16) - 1 < HLocMin)
9393  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
9394  if((TextH / 16) + 1 > HLocMax)
9395  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
9396  if((TextV / 16) - 1 < VLocMin)
9397  VLocMin = (TextV / 16) - 1;
9398  if((TextV / 16) + 1 > VLocMax)
9399  VLocMax = (TextV / 16) + 1;
9400  }
9401  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
9402  {
9403  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
9404  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
9405  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
9406  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
9407  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
9408  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
9409  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
9410  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
9411  }
9412 
9413  Utilities->CallLogPop(641);
9414 }
9415 
9416 // ---------------------------------------------------------------------------
9417 
9418 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
9419  bool &UserGraphicFoundFlag)
9420 {
9421  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
9422  TUserGraphicVector::iterator UserGraphicPtr;
9423 
9424  UserGraphicFoundFlag = false;
9425  if(!UserGraphicVector.empty())
9426  {
9427  int x = UserGraphicVector.size();
9428  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
9429  {
9430  x--;
9431  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
9432  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
9433  {
9434  UserGraphicItem = x;
9435  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
9436  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
9437  UserGraphicFoundFlag = true;
9438  Utilities->CallLogPop(2177);
9439  return;
9440  } // if ....
9441  } // for UserGraphicPtr...
9442  } // if !UserGraphicVector...
9443  Utilities->CallLogPop(2197);
9444 }
9445 
9446 // ---------------------------------------------------------------------------
9447 
9449 {
9450  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
9451  TrackElement.LogTrack(11));
9452  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
9453  int SpeedTag = TrackElement.SpeedTag;
9454 
9455  if(SpeedTag < 1)
9456  {
9457  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
9458  }
9459  switch(SpeedTag)
9460  {
9461  case 76: // t platform
9462  GraphicOutput = RailGraphics->gl76Striped;
9463  break;
9464 
9465  case 77: // h platform
9466  GraphicOutput = RailGraphics->bm77Striped;
9467  break;
9468 
9469  case 78: // v platform
9470  GraphicOutput = RailGraphics->bm78Striped;
9471  break;
9472 
9473  case 79: // r platform
9474  GraphicOutput = RailGraphics->gl79Striped;
9475  break;
9476 
9477  case 96: // concourse
9478  GraphicOutput = RailGraphics->ConcourseStriped;
9479  break;
9480 
9481  case 129: // v footbridge
9482  GraphicOutput = RailGraphics->gl129Striped;
9483  break;
9484 
9485  case 130: // h footbridge
9486  GraphicOutput = RailGraphics->gl130Striped;
9487  break;
9488 
9489  case 131: // non-station named loc
9490  GraphicOutput = RailGraphics->bmNameStriped;
9491  break;
9492 
9493  case 145: // v u'pass
9494  GraphicOutput = RailGraphics->gl145Striped;
9495  break;
9496 
9497  case 146: // h u'pass
9498  GraphicOutput = RailGraphics->gl146Striped;
9499  break;
9500 
9501  default:
9502  GraphicOutput = TrackElement.GraphicPtr;
9503  break;
9504  }
9505  Utilities->CallLogPop(642);
9506  return GraphicOutput;
9507 }
9508 
9509 // ---------------------------------------------------------------------------
9510 
9512 {
9513  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
9514  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
9515  {
9516  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
9517  }
9518  Utilities->CallLogPop(643);
9519  return TrackVector.at(At);
9520 }
9521 
9522 // ---------------------------------------------------------------------------
9523 
9525 {
9526  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
9527  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
9528  {
9529  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
9530  " in InactiveTrackElementAt");
9531  }
9532  Utilities->CallLogPop(644);
9533  return InactiveTrackVector.at(At);
9534 }
9535 
9536 // ---------------------------------------------------------------------------
9537 
9538 bool TTrack::BlankElementAt(int Caller, int At) const
9539 {
9540  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
9541  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
9542  {
9543  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
9544  }
9545  if(TrackVector.at(At).SpeedTag == 0)
9546  {
9547  Utilities->CallLogPop(645);
9548  return true;
9549  }
9550  else
9551  {
9552  Utilities->CallLogPop(646);
9553  return false;
9554  }
9555 }
9556 
9557 // ---------------------------------------------------------------------------
9558 
9559 bool TTrack::OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
9560 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
9561  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
9562  split is required a specific check is made using ThisNamedLocationLongEnoughForSplit.
9563  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
9564  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
9565 */
9566 {
9567  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationLongEnoughForSplit," + LocationName);
9568  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
9569  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
9570  TLocationNameMultiMapIterator SNIterator;
9571  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9572 
9573  if(SNRange.first == SNRange.second)
9574  {
9575  Utilities->CallLogPop(972);
9576  return false; // should have been caught earlier but include for completeness
9577  }
9578  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9579  {
9580  if(SNIterator->second < 0)
9581  continue; // exclude footcrossings
9582  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
9583  if(InactiveElement.TrackType == Concourse)
9584  continue; // only interested in locations where ActiveTrackElementName may be set
9585  THVPair HVPair;
9586  HVPair.first = InactiveElement.HLoc;
9587  HVPair.second = InactiveElement.VLoc;
9588  if(TrackMap.find(HVPair) == TrackMap.end())
9589  {
9590  throw Exception
9591  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNamedLocationLongEnoughForSplit (1)");
9592  }
9593  int TVPos = TrackMap.find(HVPair)->second;
9594  FirstNamedElement = TrackElementAt(560, TVPos);
9595  // first check linked on both sides, skip the check if not
9596  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
9597  {
9598  continue;
9599  }
9600  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
9601  // ActiveTrackElementNames are points and excluding trailing connections for points
9602  FirstNamedExitPos = 0;
9603  {
9604  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
9605  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
9606  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
9607  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
9608  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
9609  {
9610  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
9611  {
9612  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
9613  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
9614  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
9615  // success, now check FirstNamedElement link not trailing points & if so all OK
9616  {
9617  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
9618  {
9619  Utilities->CallLogPop(1002);
9620  return true;
9621  }
9622  }
9623  }
9624  }
9625  }
9626  // failed, try link 1
9627  FirstNamedExitPos = 1;
9628  {
9629  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
9630  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
9631  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
9632  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
9633  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
9634  {
9635  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
9636  {
9637  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
9638  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
9639  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
9640  // success, now check FirstNamedElement link not trailing points & if so all OK
9641  {
9642  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
9643  {
9644  Utilities->CallLogPop(1003);
9645  return true;
9646  }
9647  }
9648  }
9649  }
9650  }}
9651  Utilities->CallLogPop(1004);
9652  return false;
9653 }
9654 
9655 // ---------------------------------------------------------------------------
9656 bool TTrack::ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos,
9657  int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
9658  // for success need two linked named location elements, so that one element of each train can be at the location
9659  // FirstNamedElementPos is the input vector position and the first (if successful) of the two linked named location elements,
9660  // the second is SecondNamedElementPos, and the two linked elements are FirstNamedLinkedElementPos and SecondNamedLinkedElementPos.
9661  // the two trains will occupy these 4 elements
9662  // All are track vector positions, all but the input being references and set within the function.
9663 {
9664 /* Check sufficient elements (including TrackvectorPosition) with same ActiveTrackElementName linked together without any trailing point
9665  links and including the element FirstNamedElementPos to allow a train split. Need at least two linked ActiveTrackElementNames, with
9666  connected elements at each end, which may or may not be ActiveTrackElementNames, and no connections via point trailing links. Note that
9667  these conditions exclude opposed buffers since these not linked. Return the two train positions and exit positions for use in train
9668  splitting.
9669 */
9670  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisNamedLocationLongEnoughForSplit," + LocationName +
9671  AnsiString(FirstNamedElementPos));
9672  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
9673  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
9674 
9675  SecondNamedElementPos = -1;
9676  FirstNamedLinkedElementPos = -1;
9677  SecondNamedLinkedElementPos = -1;
9678  TLocationNameMultiMapIterator SNIterator;
9679  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9680 
9681  if(SNRange.first == SNRange.second) // i.e. location name not in map
9682  {
9683  Utilities->CallLogPop(1005);
9684  return false; // should have been caught earlier but include for completeness
9685  }
9686  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9687  {
9688  if(SNIterator->second < 0)
9689  continue; // exclude footcrossings
9690  InactiveElement = InactiveTrackElementAt(69, SNIterator->second);
9691  if(InactiveElement.TrackType == Concourse)
9692  continue; // only interested in locations where ActiveTrackElementName may be set
9693  THVPair HVPair;
9694  HVPair.first = InactiveElement.HLoc;
9695  HVPair.second = InactiveElement.VLoc;
9696  if(TrackMap.find(HVPair) == TrackMap.end())
9697  {
9698  if(InactiveElement.TrackType == NamedNonStationLocation) // added at v2.2.0 to correct the error Xeon reported on 14/07/18.
9699  // If there is a NamedNonStationLocation without an associated active track element (effectively a non-station concourse)
9700  // then it won't be found in TrackMap but it's still legitimate.
9701  {
9702  continue;
9703  }
9704  else // for anything else throw the error
9705  {
9706  throw Exception
9707  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in ThisNamedLocationLongEnoughForSplit (2)"
9708  );
9709  }
9710  }
9711  int TVPos = TrackMap.find(HVPair)->second;
9712  if(TVPos != FirstNamedElementPos)
9713  continue; // looking for an exact match
9714  FirstNamedElement = TrackElementAt(567, TVPos);
9715  // first check linked on both sides, skip the check if not
9716  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
9717  {
9718  continue;
9719  }
9720  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
9721  // ActiveTrackElementNames are points and excluding trailing connections for points
9722  FirstNamedExitPos = 0;
9723  {
9724  SecondNamedElement = TrackElementAt(568, FirstNamedElement.Conn[FirstNamedExitPos]);
9725  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
9726  FirstNamedLinkedElement = TrackElementAt(569, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
9727  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
9728  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
9729  {
9730  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
9731  {
9732  SecondNamedLinkedElement = TrackElementAt(570, SecondNamedElement.Conn[SecondNamedExitPos]);
9733  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
9734  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
9735  // success, now check FirstNamedElement link not trailing points & if so all OK
9736  {
9737  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
9738  {
9739  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
9740  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
9741  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
9742  Utilities->CallLogPop(1006);
9743  return true;
9744  }
9745  }
9746  }
9747  }
9748  }
9749  // failed, try link 1
9750  FirstNamedExitPos = 1;
9751  {
9752  SecondNamedElement = TrackElementAt(571, FirstNamedElement.Conn[FirstNamedExitPos]);
9753  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
9754  FirstNamedLinkedElement = TrackElementAt(572, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
9755  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
9756  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
9757  {
9758  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
9759  {
9760  SecondNamedLinkedElement = TrackElementAt(573, SecondNamedElement.Conn[SecondNamedExitPos]);
9761  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
9762  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
9763  // success, now check FirstNamedElement link not trailing points & if so all OK
9764  {
9765  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
9766  {
9767  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
9768  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
9769  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
9770  Utilities->CallLogPop(1007);
9771  return true;
9772  }
9773  }
9774  }
9775  }
9776  }}
9777  Utilities->CallLogPop(1008);
9778  return false;
9779 }
9780 
9781 // ---------------------------------------------------------------------------
9782 
9783 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
9784 {
9785  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
9786  TLocationNameMultiMapIterator SNIterator;
9787  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9788 
9789  if(SNRange.first != SNRange.second)
9790  {
9791  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9792  {
9793  if(SNIterator->second < 0)
9794  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
9795  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
9796  SNIterator->second).TrackType == NamedNonStationLocation))
9797  {
9798  Utilities->CallLogPop(1121);
9799  return true;
9800  }
9801  }
9802  }
9803  Utilities->CallLogPop(848);
9804  return false;
9805 }
9806 
9807 // ---------------------------------------------------------------------------
9808 
9809 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
9810 {
9811 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
9812  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
9813  "," + AnsiString(SpeedTag));
9814  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
9815  {
9816  Utilities->CallLogPop(949);
9817  return false;
9818  }
9819  bool FoundFlag;
9820  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
9821 
9822  if(!FoundFlag)
9823  {
9824  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
9825  }
9826  TTrackElement IAElement;
9827 
9828  if(SpeedTag == 68) // top sig
9829  {
9830  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
9831  {
9832  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
9833  IAElement = InactiveTrackElementAt(50, IMPair.first);
9834  else
9835  IAElement = InactiveTrackElementAt(51, IMPair.second);
9836  if(IAElement.LocationName == "")
9837  {
9838 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
9839  SignalPlatformGraphic = RailGraphics->gl76Striped;
9840  }
9841  else
9842  {
9843 // SignalPlatformGraphic = RailGraphics->Plat68;
9844  SignalPlatformGraphic = RailGraphics->gl76;
9845  }
9846  Utilities->CallLogPop(950);
9847  return true;
9848  }
9849  }
9850  else if(SpeedTag == 69) // bot sig
9851  {
9852  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
9853  {
9854  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
9855  IAElement = InactiveTrackElementAt(77, IMPair.first);
9856  else
9857  IAElement = InactiveTrackElementAt(78, IMPair.second);
9858  if(IAElement.LocationName == "")
9859  {
9860 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
9861  SignalPlatformGraphic = RailGraphics->bm77Striped;
9862  }
9863  else
9864  {
9865 // SignalPlatformGraphic = RailGraphics->Plat69;
9866  SignalPlatformGraphic = RailGraphics->bm77;
9867  }
9868  Utilities->CallLogPop(951);
9869  return true;
9870  }
9871  }
9872  else if(SpeedTag == 70) // left sig
9873  {
9874  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
9875  {
9876  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
9877  IAElement = InactiveTrackElementAt(55, IMPair.first);
9878  else
9879  IAElement = InactiveTrackElementAt(82, IMPair.second);
9880  if(IAElement.LocationName == "")
9881  {
9882 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
9883  SignalPlatformGraphic = RailGraphics->bm78Striped;
9884  }
9885  else
9886  {
9887 // SignalPlatformGraphic = RailGraphics->Plat70;
9888  SignalPlatformGraphic = RailGraphics->bm78;
9889  }
9890  Utilities->CallLogPop(952);
9891  return true;
9892  }
9893  }
9894  else if(SpeedTag == 71) // right sig
9895  {
9896  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
9897  {
9898  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
9899  IAElement = InactiveTrackElementAt(85, IMPair.first);
9900  else
9901  IAElement = InactiveTrackElementAt(86, IMPair.second);
9902  if(IAElement.LocationName == "")
9903  {
9904 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
9905  SignalPlatformGraphic = RailGraphics->gl79Striped;
9906  }
9907  else
9908  {
9909 // SignalPlatformGraphic = RailGraphics->Plat71;
9910  SignalPlatformGraphic = RailGraphics->gl79;
9911  }
9912  Utilities->CallLogPop(953);
9913  return true;
9914  }
9915  }
9916  Utilities->CallLogPop(954);
9917  return false;
9918 }
9919 
9920 // ---------------------------------------------------------------------------
9921 
9922 bool TTrack::OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
9923  // returns true if another train on NextEntryPos track of element at NextPos, whether bridge or not
9924  // false if not, if NextPos == -1, or if only own train on the track
9925 {
9926  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(NextPos) + "," +
9927  AnsiString(NextEntryPos) + "," + AnsiString(OwnTrainID));
9928  if(NextEntryPos < 0)
9929  {
9930  Utilities->CallLogPop(1348);
9931  return false;
9932  }
9933  TTrackElement TrackElement = TrackElementAt(713, NextPos);
9934 
9935  if(TrackElement.TrackType != Bridge)
9936  {
9937  Utilities->CallLogPop(1349);
9938  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
9939  }
9940 // bridge if reach here
9941  if(NextEntryPos > 1)
9942  {
9943  Utilities->CallLogPop(1350);
9944  return ((TrackElement.TrainIDOnBridgeTrackPos23 > -1) && (TrackElement.TrainIDOnBridgeTrackPos23 != OwnTrainID));
9945  }
9946  else
9947  {
9948  Utilities->CallLogPop(1351);
9949  return ((TrackElement.TrainIDOnBridgeTrackPos01 > -1) && (TrackElement.TrainIDOnBridgeTrackPos01 != OwnTrainID));
9950  }
9951 }
9952 
9953 // ---------------------------------------------------------------------------
9954 
9956 {
9957  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
9958  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
9959  {
9960  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
9961  }
9962  Utilities->CallLogPop(1483);
9963  return SelectVector.at(At);
9964 }
9965 
9966 // ---------------------------------------------------------------------------
9967 
9968 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
9969  // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
9970 {
9971  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
9972  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
9973  bool FoundFlag = false;
9974  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
9975  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
9976 
9977  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
9978  Utilities->CallLogPop(1538);
9979  return FoundFlag;
9980 }
9981 
9982 // ---------------------------------------------------------------------------
9983 
9984 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
9985 {
9986 // return true if find an inactive element called 'Name'
9987  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
9988  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
9989  bool FoundFlag = false;
9990 
9991  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9992  {
9993  if(InactiveTrackVector.at(x).LocationName == Name)
9994  {
9995  FoundFlag = true;
9996  int V = InactiveTrackVector.at(x).VLoc;
9997  int H = InactiveTrackVector.at(x).HLoc;
9998  if(V > VLocHi)
9999  VLocHi = V;
10000  if(V < VLocLo)
10001  VLocLo = V;
10002  if(H < HLoc)
10003  HLoc = H;
10004  }
10005  }
10006  if(FoundFlag)
10007  {
10008  VPosHi = 16 * VLocHi;
10009  VPosLo = 16 * VLocLo;
10010  HPos = 16 * HLoc;
10011  Utilities->CallLogPop(1562);
10012  return true;
10013  }
10014  else
10015  {
10016  Utilities->CallLogPop(1563);
10017  return false;
10018  }
10019 }
10020 
10021 // ---------------------------------------------------------------------------
10022 
10023 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
10024 {
10025 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
10026 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
10027  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
10028  AnsiString(EndTVPosition));
10029  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
10030  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
10031 
10032 // get H & V values for the element adjacent to Link[0] & Link[1]
10033  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
10034  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
10035  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
10036  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
10037 
10038 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
10039  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
10040  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
10041  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
10042  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
10043 
10044  if(Link0Squares <= Link1Squares)
10045  {
10046  Utilities->CallLogPop(1851);
10047  return 0;
10048  }
10049  else
10050  {
10051  Utilities->CallLogPop(1852);
10052  return 1;
10053  }
10054 }
10055 
10056 // ---------------------------------------------------------------------------
10057 
10058 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
10059 { // element can be points or any other type
10060  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
10061  AnsiString(LinkPos));
10062  Derail = false;
10063  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
10064 
10065  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
10066  {
10067  if(TE.Attribute == 0)
10068  {
10069  Utilities->CallLogPop(663);
10070  return 1; // Att == 0 & ExitPos == 1 represent straight
10071  }
10072  else
10073  {
10074  Utilities->CallLogPop(664);
10075  return 3; // Att == 1 & ExitPos == 3 represent diverging
10076  }
10077  }
10078  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
10079  {
10080  if((LinkPos == 1) && (TE.Attribute == 0))
10081  {
10082  Utilities->CallLogPop(665);
10083  return 0; // Att == 0 represents straight
10084  }
10085  else if(LinkPos == 1)
10086  {
10087  Derail = true;
10088  Utilities->CallLogPop(666);
10089  return 0;
10090  }
10091  else if((LinkPos == 3) && (TE.Attribute == 1))
10092  {
10093  Utilities->CallLogPop(667);
10094  return 0;
10095  }
10096  else if(LinkPos == 3)
10097  {
10098  Derail = true;
10099  Utilities->CallLogPop(668);
10100  return 0;
10101  }
10102  }
10103  else if(LinkPos == 0)
10104  {
10105  Utilities->CallLogPop(669);
10106  return 1;
10107  }
10108  else if(LinkPos == 1)
10109  {
10110  Utilities->CallLogPop(670);
10111  return 0;
10112  }
10113  else if(LinkPos == 2)
10114  {
10115  Utilities->CallLogPop(671);
10116  return 3;
10117  }
10118  else if(LinkPos == 3)
10119  {
10120  Utilities->CallLogPop(672);
10121  return 2;
10122  }
10123  throw Exception("Error, failure in GetExitPos"); // should never reach here
10124 }
10125 
10126 // ----------------------------------------------------------------------------
10127 
10129 {
10130  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
10131  LCVector.clear();
10132  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
10133  {
10134  if(InactiveTrackVector.at(x).TrackType == LevelCrossing)
10135  {
10136  LCVector.push_back(x);
10137  }
10138  }
10139  Utilities->CallLogPop(1931);
10140  return;
10141 }
10142 
10143 // ---------------------------------------------------------------------------
10144 
10145 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
10146 /*
10147  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
10148  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
10149  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
10150  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
10151 */
10152 {
10153  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
10154  AnsiString(Link));
10155  bool FoundFlag;
10156 
10157  TrainID = -1;
10158  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
10159 
10160  if(!FoundFlag)
10161  {
10162  Utilities->CallLogPop(2001);
10163  return false;
10164  }
10165  TTrackElement TE = TrackElementAt(882, VecPos);
10166 
10167  TrainID = TE.TrainIDOnElement;
10168  if(TE.TrackType == Bridge)
10169  {
10170  if(TE.TrainIDOnElement > -1)
10171  {
10172  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
10173  {
10174  TrainID = TE.TrainIDOnBridgeTrackPos01;
10175  }
10176  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
10177  {
10178  TrainID = TE.TrainIDOnBridgeTrackPos23;
10179  }
10180  else
10181  TrainID = -1; // shouldn't ever reach here but be safe
10182  }
10183  }
10184  if(TrainID == -1)
10185  {
10186  Utilities->CallLogPop(2002);
10187  return false;
10188  }
10189 // now get the train
10190  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
10191 
10192  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
10193  {
10194  Utilities->CallLogPop(2003);
10195  return true;
10196  }
10197  TrainID = -1;
10198  Utilities->CallLogPop(2004);
10199  return false;
10200 }
10201 
10202 // ---------------------------------------------------------------------------
10203 
10204 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
10205 /* New at v1.2.0
10206  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
10207  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
10208  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
10209  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
10210  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
10211  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
10212  Each of these is examined in turn for each route element in the relevant position.
10213 */
10214 {
10215  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
10216  "," + AnsiString(DiagonalLinkNumber));
10217  TrainID = -1;
10218  TPrefDirElement TempPrefDirElement;
10219  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
10220 
10221  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
10222  {
10223  Utilities->CallLogPop(2027);
10224  return true;
10225  }
10226 
10227  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
10228  {
10229  Utilities->CallLogPop(2028);
10230  return true;
10231  }
10232 
10233  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
10234  {
10235  Utilities->CallLogPop(2029);
10236  return true;
10237  }
10238 
10239  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
10240  {
10241  Utilities->CallLogPop(2030);
10242  return true;
10243  }
10244 
10245  Utilities->CallLogPop(2031);
10246  return false;
10247 }
10248 
10249 // ---------------------------------------------------------------------------
10250 
10251 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
10252 {
10253  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
10254  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
10255  TUserGraphicItem UGI;
10256  AnsiString JustFileName = "";
10257 
10258  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
10259  {
10260  UGI = UserGraphicVectorAt(17, x);
10261  int LastDelim = UGI.FileName.LastDelimiter('\\');
10262  if(LastDelim == 0) // can't find it so skip this item
10263  {
10264  continue;
10265  }
10266  else
10267  {
10268  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
10269  }
10270  Utilities->SaveFileString(VecFile, JustFileName);
10271  Utilities->SaveFileInt(VecFile, UGI.HPos);
10272  Utilities->SaveFileInt(VecFile, UGI.VPos);
10273  }
10274  Utilities->CallLogPop(2178);
10275 }
10276 
10277 // ---------------------------------------------------------------------------
10278 
10279 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
10280 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
10281 {
10282  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
10283  int NumPlats = 0;
10284  TTrackElement TempElement;
10285  int TempInt;
10286 
10287  typedef std::list<int> TNamePosList;
10288  TNamePosList NamePosList;
10289  typedef TNamePosList::iterator TNPLIt;
10290  TNPLIt NPLIt;
10291  typedef std::list<int> TOnePlatList;
10292  TOnePlatList OnePlatList;
10293  typedef TOnePlatList::iterator TOPLIt;
10294  TOPLIt OPLIt;
10295 
10296  NamePosList.clear();
10297  OnePlatList.clear();
10298  for(unsigned int x = 0; x < TrackVector.size(); x++)
10299  {
10300  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
10301  {
10302  NamePosList.push_back(x);
10303  }
10304  }
10305  //NamePosList complete
10306 
10307  if(!NamePosList.empty()) //first value for the loop examination
10308  {
10309  OnePlatList.push_back(NamePosList.back());
10310  NamePosList.pop_back(); //erase from NPV as done with it here
10311  }
10312 
10313  while(!OnePlatList.empty()) //loop to examine all linked elements
10314  {
10315  TempInt = OnePlatList.front();
10316  TempElement = TrackElementAt(989, TempInt);
10317 
10318  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
10319  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
10320  {
10321  OnePlatList.push_back(TempElement.Conn[0]);
10322  NamePosList.erase(NPLIt);
10323  }
10324  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
10325  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
10326  {
10327  OnePlatList.push_back(TempElement.Conn[1]);
10328  NamePosList.erase(NPLIt);
10329  }
10330  //here when loaded any connecting links into OnePlatList, so can erase the front element
10331  OnePlatList.erase(OnePlatList.begin());
10332  if(OnePlatList.empty())
10333  {
10334  NumPlats++; //finished with current linked elements so can increment NumPlats
10335  if(!NamePosList.empty())
10336  {
10337  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
10338  NamePosList.pop_back(); //erase from NPV as done with it there
10339  }
10340  }
10341  }
10342  Utilities->CallLogPop(2218);
10343  return NumPlats;
10344 }
10345 
10346 // ---------------------------------------------------------------------------
10347 // UserGraphic, PrefDir & Route functions
10348 // ---------------------------------------------------------------------------
10349 
10351 {
10352  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
10353  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
10354  {
10355  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
10356  }
10357  Utilities->CallLogPop(2194);
10358  return UserGraphicVector.at(At);
10359 }
10360 
10361 // ---------------------------------------------------------------------------
10362 
10363 int TOnePrefDir::LastElementNumber(int Caller) const
10364 {
10365  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
10366  int RetVal = PrefDirVector.size() - 1;
10367 
10368  if(RetVal < 0)
10369  {
10370  throw Exception("Return value negative in call to LastElementNumber");
10371  }
10372  Utilities->CallLogPop(114);
10373  return RetVal;
10374 }
10375 
10376 // ---------------------------------------------------------------------------
10378 {
10379  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
10380  if(PrefDirVector.empty())
10381  {
10382  throw Exception("PrefDirVector empty in call to LastElementPtr");
10383  }
10384  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
10385 
10386  Utilities->CallLogPop(115);
10387  return RetIT;
10388 }
10389 
10390 // ---------------------------------------------------------------------------
10392 {
10393  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
10394  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
10395  {
10396  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
10397  }
10398  Utilities->CallLogPop(116);
10399  return PrefDirVector.at(At);
10400 }
10401 
10402 // ---------------------------------------------------------------------------
10404 {
10405  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
10406  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
10407  {
10408  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
10409  " in GetModifiablePrefDirElementAt");
10410  }
10411  Utilities->CallLogPop(117);
10412  return PrefDirVector.at(At);
10413 }
10414 
10415 // ---------------------------------------------------------------------------
10417 {
10418  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
10419  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
10420  {
10421  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
10422  }
10423  Utilities->CallLogPop(118);
10424  return SearchVector.at(At);
10425 }
10426 
10427 // ---------------------------------------------------------------------------
10429 {
10430  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
10431  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
10432  {
10433  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
10434  }
10435  Utilities->CallLogPop(119);
10436  return SearchVector.at(At);
10437 }
10438 
10439 // ---------------------------------------------------------------------------
10440 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
10441 /*
10442  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
10443  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
10444  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
10445  set in later functions.
10446 */
10447 {
10448  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
10449  ClearPrefDir();
10450  int TrackVectorPosition;
10451  TTrackElement TrackElement;
10452 
10453  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
10454  {
10455  Utilities->CallLogPop(126);
10456  return false;
10457  }
10458 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
10459  if(TrackElement.TrackType == Points)
10460  {
10461  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
10462  //it isn't known which trailing edge is the required PrefDir - could use the straight as
10463  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
10464  //best to prevent it to avoid problems
10465  Utilities->CallLogPop(127);
10466  return false;
10467  }
10468 */
10469  TPrefDirElement PrefDirElement(TrackElement);
10470 
10471  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
10472  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
10473  StorePrefDirElement(1, PrefDirElement); // enter first element
10474 // Note that ELink not set even if a buffer or continuation - these set in
10475 // ConvertPrefDirSearchVector after 2nd element added
10476 
10477  Utilities->CallLogPop(128);
10478  return true;
10479 }
10480 
10481 // ---------------------------------------------------------------------------
10482 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
10483 
10484 /*
10485  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
10486  Examine the last element in the PrefDirvector, if ELink not set (start element) do an immediate
10487  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
10488  with setting the PrefDir vector, & return true. Also set FinishElement if found element was a buffer or continuation,
10489  so that the calling function knows that the PrefDir is complete.
10490  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
10491  SearchForPrefDir to examine all branches. If succeed set PrefDirvector & finishelement as appropriate.
10492  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
10493  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
10494  ConvertPrefDirSearchVector to set PrefDirVector. Set FinishElement appropriately.
10495  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
10496  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
10497  find the required element return false. CheckCount is used to keep track of set values to allow check later.
10498 */
10499 
10500 {
10501  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
10502  FinishElement = false;
10503  int TrackVectorPosition;
10504 
10505  TotalSearchCount = 0;
10506  TTrackElement TrackElement, TempTrackElement;
10507 
10508  if(PrefDirVector.size() == 0)
10509  {
10510  Utilities->CallLogPop(129);
10511  return false;
10512  }
10513  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
10514  {
10515  Utilities->CallLogPop(130);
10516  return false;
10517  }
10518 
10519 // set the search limits using the last stored element in PrefDirVector as the start point
10520 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
10521 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
10522 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
10523 
10524  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
10525 
10526  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
10527  {
10528  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
10529  SearchLimitHighH = TrackElement.HLoc + 15;
10530  }
10531  else
10532  {
10533  SearchLimitLowH = TrackElement.HLoc - 15;
10534  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
10535  }
10536 
10537  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
10538  {
10539  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
10540  SearchLimitHighV = TrackElement.VLoc + 15;
10541  }
10542  else
10543  {
10544  SearchLimitLowV = TrackElement.VLoc - 15;
10545  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
10546  }
10547 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
10548  check & TotalSearchCounts check
10549  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
10550  {
10551  ShowMessage("Unable to reach the selected element - too far ahead");
10552  Utilities->CallLogPop(1692);
10553  return false;
10554  }
10555 */
10556 // get last PrefDir element
10557  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
10558  {
10559  // check if TrackElement adjacent to any of the 4 XLinkPos'
10560  for(int x = 0; x < 4; x++)
10561  {
10562  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
10563  {
10564  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
10565  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
10566  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
10567  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
10568  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
10569  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
10570  // shouldn't ever get it in a serious railway though.
10571 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
10572  }
10573  }
10574  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
10575  {
10576  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
10577  SearchVector.clear(); // use this & convert to set all PrefDir element values
10578  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
10579  {
10581  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10582  {
10583  FinishElement = true;
10584  }
10585  Utilities->CallLogPop(131);
10586  return true;
10587  }
10588  } // not an adjacent element
10589 
10590  // now check each of the 4 possible XLinkPos values
10591  for(int x = 0; x < 4; x++)
10592  {
10593  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
10594  {
10595  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
10596  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
10597  SearchVector.clear();
10598  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
10599  {
10601  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10602  {
10603  FinishElement = true;
10604  }
10605  Utilities->CallLogPop(132);
10606  return true;
10607  }
10608  }
10609  } // here if checked all possible exits without success
10610  ShowMessage(
10611  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
10612  Utilities->CallLogPop(133);
10613  return false;
10614  }
10615 // dealt above with LastPrefDirElement being the start element (which can be points)
10616 
10617  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
10618  .ELinkPos] == Lead)) // leading point
10619  {
10620  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
10621  {
10622  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
10623  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
10624  // can't be buffers or gap if points
10625  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
10626  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
10627  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
10628  SearchVector.clear();
10629  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
10630  {
10632  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10633  {
10634  FinishElement = true;
10635  }
10636  Utilities->CallLogPop(134);
10637  return true;
10638  }
10639  }
10640  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
10641  {
10642  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
10643  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
10644  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
10645  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
10646  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
10647  SearchVector.clear();
10648  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
10649  {
10651  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10652  {
10653  FinishElement = true;
10654  }
10655  Utilities->CallLogPop(135);
10656  return true;
10657  }
10658  }
10659 // above dealt with immediate finds for leading point,
10660 // now deal with ordinary searches for leading point
10661  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
10662  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
10663  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
10664  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
10665  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
10666  SearchVector.clear();
10667  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
10668  {
10670  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10671  {
10672  FinishElement = true;
10673  }
10674  Utilities->CallLogPop(136);
10675  return true;
10676  }
10677  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
10678  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
10679  // note that CheckCount already increased to allow for XLinkPos & XLink
10680  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
10681  SearchVector.clear();
10682  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
10683  {
10685  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10686  {
10687  FinishElement = true;
10688  }
10689  Utilities->CallLogPop(137);
10690  return true;
10691  }
10692 // here if failed to find match for leading point
10693  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
10694  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
10695  ShowMessage(
10696  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
10697  Utilities->CallLogPop(138);
10698  return false;
10699  }
10700 // leading point fully dealt with above
10701 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
10702 // separately as covered in ordinary search.
10703 
10704  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
10705  SearchVector.clear();
10706 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
10707  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
10708  {
10710  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10711  {
10712  FinishElement = true;
10713  }
10714  Utilities->CallLogPop(139);
10715  return true;
10716  }
10717  ShowMessage(
10718  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
10719  Utilities->CallLogPop(140);
10720  return false; // failed to find required element
10721 }
10722 
10723 // ---------------------------------------------------------------------------
10724 
10725 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
10726 /*
10727  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
10728  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
10729  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
10730  Keep a count of entries in SearchVector during the current function call, so that this number can be
10731  erased for an unproductive branch search.
10732  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
10733  element. If so save it & return true. If not check if buffer, continuation, or earlier position
10734  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
10735  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
10736  If not any of above, store element in searchvector, set the new current element values from the
10737  SearchElement, then go back to the while loop for the next step in the search.
10738 */
10739 {
10740  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
10741  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
10742  int VectorCount = 0;
10743 
10744  while(true)
10745  {
10746  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
10747  {
10748  for(int x = 0; x < VectorCount; x++)
10749  SearchVector.erase(SearchVector.end() - 1);
10750  Utilities->CallLogPop(141);
10751  return false;
10752  }
10753  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
10754  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
10755  TPrefDirElement SearchElement(NextTrackElement);
10756  SearchElement.TrackVectorPosition = NextPosition;
10757  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
10758  SearchElement.ELinkPos = NextELinkPos;
10759  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
10760  int NextXLinkPos;
10761  if(SearchElement.ELinkPos == 0)
10762  NextXLinkPos = 1;
10763  if(SearchElement.ELinkPos == 1)
10764  NextXLinkPos = 0;
10765  if(SearchElement.ELinkPos == 2)
10766  NextXLinkPos = 3;
10767  if(SearchElement.ELinkPos == 3)
10768  NextXLinkPos = 2;
10769  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
10770  {
10771  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
10772  // but may be buffers, continuation or gap
10773  SearchElement.XLinkPos = NextXLinkPos;
10774  }
10775 // can't set XLink or XLinkPos yet if the element is a leading point.
10776 // check if found it
10777  if(SearchElement.TrackVectorPosition == RequiredPosition)
10778  {
10779  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
10780  VectorCount++; // not really needed but include for tidyness
10781  TotalSearchCount++;
10782  Utilities->CallLogPop(142);
10783  return true;
10784  }
10785 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
10786 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
10787 // at a time - drop this
10788 /*
10789  if(PrefDirVector.size() > 200)
10790  {
10791  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
10792  Utilities->CallLogPop(1419);
10793  return false;
10794  }
10795 */
10796 // check if a buffer or continuation
10797  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
10798  {
10799  for(int x = 0; x < VectorCount; x++)
10800  SearchVector.erase(SearchVector.end() - 1);
10801  Utilities->CallLogPop(143);
10802  return false;
10803  }
10804 // check if reached an earlier position on search PrefDir with same entry value
10805  for(unsigned int x = 0; x < SearchVector.size(); x++)
10806  {
10807  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
10808  {
10809  for(int x = 0; x < VectorCount; x++)
10810  SearchVector.erase(SearchVector.end() - 1);
10811  Utilities->CallLogPop(144);
10812  return false;
10813  }
10814  }
10815 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
10816 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
10817  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
10818  {
10819  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
10820  {
10821  for(int x = 0; x < VectorCount; x++)
10822  SearchVector.erase(SearchVector.end() - 1);
10823  Utilities->CallLogPop(1417);
10824  return false;
10825  }
10826  }
10827 
10828 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
10829 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
10830 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
10832  {
10833  for(int x = 0; x < VectorCount; x++)
10834  SearchVector.erase(SearchVector.end() - 1);
10835  Utilities->CallLogPop(1691);
10836  return false;
10837  }
10838 
10839 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
10840  if(SearchVector.size() > 150)
10841  {
10842  for(int x = 0; x < VectorCount; x++)
10843  SearchVector.erase(SearchVector.end() - 1);
10844  Utilities->CallLogPop(1418);
10845  return false;
10846  }
10847 // check if reached a leading point
10848  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
10849  {
10850 // push element with XLink set to position [1]
10851  SearchElement.XLink = SearchElement.Link[1];
10852  SearchElement.XLinkPos = 1;
10853  SearchVector.push_back(SearchElement);
10854  VectorCount++;
10855  TotalSearchCount++;
10856  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
10857  // Note that have to use a TTrackElement in the recursive search, so SearchElement
10858  // can't be used. NextTrackElement is the corresponding TTrackElement.
10859  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
10860  {
10861  Utilities->CallLogPop(145);
10862  return true;
10863  }
10864  else
10865  {
10866 // remove leading point with XLinkPos [1]
10867  SearchVector.erase(SearchVector.end() - 1);
10868  VectorCount--;
10869 // push element with XLink set to position [3]
10870  SearchElement.XLink = SearchElement.Link[3];
10871  SearchElement.XLinkPos = 3;
10872  SearchVector.push_back(SearchElement);
10873  VectorCount++;
10874  TotalSearchCount++;
10875 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
10876  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
10877  {
10878  Utilities->CallLogPop(146);
10879  return true;
10880  }
10881  else
10882  {
10883  for(int x = 0; x < VectorCount; x++)
10884  SearchVector.erase(SearchVector.end() - 1);
10885  Utilities->CallLogPop(147);
10886  return false;
10887  }
10888  }
10889  } // if leading point
10890 // here if ordinary element, push it, inc vector & update CurrentTrackElement
10891 // ready for next element on PrefDir
10892  SearchVector.push_back(SearchElement);
10893  VectorCount++;
10894  TotalSearchCount++;
10895  XLinkPos = NextXLinkPos;
10896  CurrentTrackElement = SearchElement;
10897  } // while(true)
10898 }
10899 
10900 // ---------------------------------------------------------------------------
10901 
10903 /*
10904  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
10905  for each element on the search PrefDir, though if the last element is a leading point
10906  then the final XLink won't be set.
10907  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
10908  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
10909  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
10910 */
10911 {
10912  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
10913  if(SearchVector.size() == 0)
10914  {
10915  throw Exception("Error, SearchVector empty");
10916  }
10917 // get first SearchElement in order to set last PrefDirelement
10918  TPrefDirElement SearchElement = SearchVector.at(0);
10919 
10920 // set last PrefDir element XLink & ELink values if not already set
10921 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
10922  for(int x = 0; x < 4; x++)
10923  {
10924  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
10925  {
10926  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
10927  {
10928  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
10929  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
10930  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
10931  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
10932  }
10933  int ELinkPos;
10934  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
10935  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
10936  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
10937  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
10938  ELinkPos = 0;
10939  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
10940  ELinkPos = 3;
10941  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
10942  ELinkPos = 2;
10943  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
10944  {
10945  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
10946  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
10947  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
10948  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
10949  }
10950  break; // no point going any further
10951  }
10952  }
10953 // set EXNumber for last PrefDir element, unless already set
10954 // won't be set if was first element or a leading point
10955  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
10956  {
10957 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
10958  int EXArray[32][2] = {
10959  {4,6},{2,8}, //horizontal & vertical
10960  {2,4},{6,2},{8,6},{4,8}, //sharp curves
10961  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
10962  {1,9},{3,7} //forward & reverse diagonals
10963 */
10964 
10965  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
10966  {
10967  throw Exception("Error in EntryExitNumber 1");
10968  }
10969 
10970  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
10971  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
10972  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
10973  }
10974 // Last PrefDir element now complete
10975 
10976 // construct remaining PrefDir elements from searchvector
10977  for(unsigned int x = 0; x < SearchVector.size(); x++)
10978  {
10979  SearchElement = SearchVector.at(x);
10980  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
10981  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
10982  PrefDirElement.ELink = SearchElement.ELink;
10983  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
10984  PrefDirElement.XLink = SearchElement.XLink;
10985  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
10986 // if XLink & XLinkPos not set don't account for them in CheckCount
10987  if(PrefDirElement.XLink == -1)
10988  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
10989  // & TrackVectorPosition
10990  else
10991  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
10992  // XLink, XLinkPos, TrackVectorPosition
10993 
10994 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
10995  if(PrefDirElement.XLink != -1)
10996  {
10997  if(!(PrefDirElement.EntryExitNumber()))
10998  {
10999  throw Exception("Error in EntryExitNumber 2");
11000  }
11001  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
11002  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
11003  PrefDirElement.CheckCount++;
11004  // all values now incorporated if not a leading point
11005  }
11006 // store PrefDir element
11007  StorePrefDirElement(2, PrefDirElement);
11008  }
11009 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
11010  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
11011  {
11012  if(ValidatePrefDir(2))
11013  {;
11014  } // error messages given within function
11015  }
11017 /* drop this, check dropped from search
11018  if(PrefDirVector.size() > 200)
11019  {
11020  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
11021  }
11022 */
11023  Utilities->CallLogPop(148);
11024 }
11025 
11026 // ---------------------------------------------------------------------------
11027 
11028 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
11029 /*
11030  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
11031  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
11032 */
11033 {
11034  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
11035  LeadingPoints = false;
11036  if(PrefDirVector.empty())
11037  {
11038  Utilities->CallLogPop(1786);
11039  return false; // should never be empty but allow for it for safety
11040  }
11041  if(PrefDirVector.size() == 1)
11042  {
11043  Utilities->CallLogPop(149);
11044  return false; // can't end if only one element
11045  }
11046 /*
11047  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
11048  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
11049  {
11050  Utilities->CallLogPop(150);
11051  return true;
11052  }
11053 */
11054 // allow for anything but leading points
11055  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
11056  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
11057  {
11058  Utilities->CallLogPop(1776);
11059  return true;
11060  }
11061  else
11062  {
11063  LeadingPoints = true;
11064  Utilities->CallLogPop(151);
11065  return false;
11066  }
11067 }
11068 
11069 // ---------------------------------------------------------------------------
11070 
11072 /*
11073  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
11074  and that every element is connected to the next element
11075 */
11076 {
11077  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
11078  int Position;
11079  AnsiString ErrorString;
11080  bool Error = false;
11081 
11082  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11083  {
11084  if(PrefDirVector.at(x).HLoc == -2000000000)
11085  {
11086  Error = true;
11087  ErrorString = "HLoc";
11088  Position = x;
11089  }
11090  if(PrefDirVector.at(x).VLoc == -2000000000)
11091  {
11092  Error = true;
11093  ErrorString = "VLoc";
11094  Position = x;
11095  }
11096  if(PrefDirVector.at(x).ELink == -1)
11097  {
11098  Error = true;
11099  ErrorString = "ELink";
11100  Position = x;
11101  }
11102  if(PrefDirVector.at(x).ELinkPos == -1)
11103  {
11104  Error = true;
11105  ErrorString = "ELinkPos";
11106  Position = x;
11107  }
11108  if(PrefDirVector.at(x).XLink == -1)
11109  {
11110  Error = true;
11111  ErrorString = "XLink";
11112  Position = x;
11113  }
11114  if(PrefDirVector.at(x).XLinkPos == -1)
11115  {
11116  Error = true;
11117  ErrorString = "XLinkPos";
11118  Position = x;
11119  }
11120  if(PrefDirVector.at(x).SpeedTag == 0)
11121  {
11122  Error = true;
11123  ErrorString = "Tag";
11124  Position = x;
11125  }
11126  if(PrefDirVector.at(x).TrackVectorPosition == -1)
11127  {
11128  Error = true;
11129  ErrorString = "TrackVectorPosition";
11130  Position = x;
11131  }
11132  if(PrefDirVector.at(x).EXNumber == -1)
11133  {
11134  Error = true;
11135  ErrorString = "EXNumber";
11136  Position = x;
11137  }
11138  if(PrefDirVector.at(x).CheckCount != 9)
11139  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
11140  {
11141  Error = true;
11142  ErrorString = "CheckCount";
11143  Position = x;
11144  }
11145 // extra checks
11146  if(PrefDirVector.at(x).EXGraphicPtr == 0)
11147  {
11148  Error = true;
11149  ErrorString = "EntryGraphicPtr";
11150  Position = x;
11151  }
11152  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
11153  {
11154  Error = true;
11155  ErrorString = "EntryDirectionGraphicPtr";
11156  Position = x;
11157  }
11158 // end of extra checks
11159  if(x > 0)
11160  {
11161  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
11162  {
11163  Error = true;
11164  ErrorString = "Last XLink not connected to this element";
11165  Position = x;
11166  }
11167  }
11168  }
11169  if(Error)
11170  {
11171  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
11172  }
11173  else
11174  {
11175  Utilities->CallLogPop(153);
11176  return true;
11177  }
11178 }
11179 
11180 // ---------------------------------------------------------------------------
11181 
11182 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
11183 /*
11184  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
11185  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
11186  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
11187  or a leading point.
11188 */
11189 {
11190  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11191  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
11192  {
11193  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
11194  {
11195  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
11196  {
11197  ErasePrefDirElementAt(1, PrefDirVecPos);
11198  }
11199  if(PrefDirVector.size() == 0)
11200  {
11201  Utilities->CallLogPop(154);
11202  return true;
11203  }
11204  if(PrefDirVector.size() == 1)
11205  {
11206  PrefDirVector.at(x - 1).ELinkPos = -1;
11207  PrefDirVector.at(x - 1).ELink = -1;
11208  PrefDirVector.at(x - 1).XLinkPos = -1;
11209  PrefDirVector.at(x - 1).XLink = -1;
11210  PrefDirVector.at(x - 1).EXNumber = -1;
11211  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
11212  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
11213  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
11214  Utilities->CallLogPop(155);
11215  return true;
11216  }
11217  // here with truncate element not first element, so ELink & ELinkPos set
11218  // unset XLink & Pos if a leading point
11219  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
11220  {
11221  PrefDirVector.at(x - 1).XLinkPos = -1;
11222  PrefDirVector.at(x - 1).XLink = -1;
11223  PrefDirVector.at(x - 1).EXNumber = -1;
11224  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
11225  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
11226  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
11227  Utilities->CallLogPop(156);
11228  return true;
11229  }
11230  Utilities->CallLogPop(157);
11231  return true;
11232  }
11233  }
11234  Utilities->CallLogPop(158);
11235  return false;
11236 }
11237 
11238 // ---------------------------------------------------------------------------
11239 
11240 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
11241  const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
11242 /*
11243  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
11244  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
11245  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
11246  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
11247  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
11248  displayed.
11249 */
11250 {
11251  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
11252  AnsiString((short)BuildingPrefDir));
11253  int HPos, VPos;
11254 
11255  if(PrefDirSize() == 0)
11256  {
11257  Utilities->CallLogPop(159);
11258  return;
11259  }
11260  for(unsigned int x = 0; x < PrefDirSize(); x++)
11261  {
11262  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
11263 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
11264 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
11265 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
11266  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
11267  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
11268  // only the front half of which will be overplotted by the back of the train, then when the train is
11269  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
11270  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
11271  {
11272  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
11273  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
11274  {
11275  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
11276  }
11277  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
11278  // Route, no direction if a single element
11279  {
11280  if(x == 0)
11281  {
11282  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
11283  }
11284  if(x == (PrefDirSize() - 1))
11285  {
11286  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
11287  }
11288  }
11289  }
11290  }
11291 
11292 // set start & end element colours if building a PrefDir
11293  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
11294  {
11295  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
11296  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
11297  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
11298  // set last element colour
11299  if(PrefDirSize() > 1)
11300  {
11301  unsigned int LatestPos = PrefDirSize() - 1;
11302  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
11303  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
11304  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
11305  }
11306  }
11307  Disp->Update();
11308  Utilities->CallLogPop(160);
11309 }
11310 
11311 // ---------------------------------------------------------------------------
11312 
11314 /*
11315  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
11316  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
11317 */
11318 {
11319  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
11320  if(PrefDirSize() == 0)
11321  {
11322  Utilities->CallLogPop(1547);
11323  return;
11324  }
11325 
11326  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
11327  bool FoundFlag;
11329  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
11330 
11331  while(MMIT != PrefDir4MultiMap.end())
11332  {
11333  H = MMIT->first.first;
11334  V = MMIT->first.second;
11335  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
11336  // always found in order, any missing have PrefDirPosx == -1
11337  if(PrefDirPos0 > -1)
11338  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
11339  if(PrefDirPos1 > -1)
11340  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
11341  if(PrefDirPos2 > -1)
11342  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
11343  if(PrefDirPos3 > -1)
11344  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
11345  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
11346  { // need to plot all 4 in order to obtain all the direction graphics
11347  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
11348  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
11349  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
11350  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
11351  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
11352  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
11353  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
11354  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
11355  MMIT++;
11356  MMIT++;
11357  MMIT++;
11358  MMIT++;
11359  }
11360  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
11361  {
11362  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
11363  { // 0 & 1 constitute the bidirectional PrefDir
11364  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
11365  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
11366  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
11367  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
11368  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
11369  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
11370  MMIT++;
11371  MMIT++;
11372  MMIT++;
11373  }
11374  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
11375  { // 0 & 2 constitute the bidirectional PrefDir
11376  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
11377  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
11378  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
11379  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
11380  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
11381  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
11382  MMIT++;
11383  MMIT++;
11384  MMIT++;
11385  }
11386  else
11387  { // 1 & 2 constitute the bidirectional PrefDir
11388  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
11389  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
11390  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
11391  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
11392  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
11393  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
11394  MMIT++;
11395  MMIT++;
11396  MMIT++;
11397  }
11398  }
11399  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
11400  {
11401  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
11402  { // 0 & 1 constitute the bidirectional PrefDir
11403  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
11404  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
11405  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
11406  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
11407  MMIT++;
11408  MMIT++;
11409  }
11410  else
11411  { // 2 unidirectional PrefDirs
11412  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
11413  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
11414  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
11415  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
11416  MMIT++;
11417  MMIT++;
11418  }
11419  }
11420  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
11421  {
11422  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
11423  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
11424  MMIT++;
11425  }
11426  }
11427  Disp->Update();
11428  Utilities->CallLogPop(1548);
11429 }
11430 
11431 // ---------------------------------------------------------------------------
11432 
11433 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
11434 {
11435  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
11436  int TempInt;
11437 
11438  ClearPrefDir();
11439  int NumberOfPrefDirElements = 0;
11440 
11441  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
11442  for(int x = 0; x < NumberOfPrefDirElements; x++)
11443  {
11444  VecFile >> TempInt; // TrackVectorPosition
11445  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
11446  LoadPrefDirElement.TrackVectorPosition = TempInt;
11447  VecFile >> TempInt;
11448  LoadPrefDirElement.ELink = TempInt;
11449  VecFile >> TempInt;
11450  LoadPrefDirElement.ELinkPos = TempInt;
11451  VecFile >> TempInt;
11452  LoadPrefDirElement.XLink = TempInt;
11453  VecFile >> TempInt;
11454  LoadPrefDirElement.XLinkPos = TempInt;
11455  VecFile >> TempInt;
11456  LoadPrefDirElement.EXNumber = TempInt;
11457  VecFile >> TempInt;
11458  LoadPrefDirElement.CheckCount = TempInt;
11459  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
11460  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
11461  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
11462  if(!(LoadPrefDirElement.IsARoute))
11463  {
11464  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
11465  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
11466  }
11467  else
11468  {
11469  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
11470  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
11471  LoadPrefDirElement.PrefDirRoute);
11472  }
11473  StorePrefDirElement(5, LoadPrefDirElement);
11474  Utilities->LoadFileString(VecFile); // marker
11475  }
11477  Utilities->CallLogPop(161);
11478 }
11479 
11480 // ---------------------------------------------------------------------------
11481 
11482 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
11483 {
11484  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
11485  int TempInt;
11486 
11487  ClearPrefDir();
11488  int NumberOfPrefDirElements = 0;
11489 
11490  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
11491  for(int x = 0; x < NumberOfPrefDirElements; x++)
11492  {
11493  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
11494  VecFile >> TempInt; // TrackVectorPosition
11495  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt));
11496  LoadPrefDirElement.TrackVectorPosition = TempInt;
11497  VecFile >> TempInt;
11498  LoadPrefDirElement.ELink = TempInt;
11499  VecFile >> TempInt;
11500  LoadPrefDirElement.ELinkPos = TempInt;
11501  VecFile >> TempInt;
11502  LoadPrefDirElement.XLink = TempInt;
11503  VecFile >> TempInt;
11504  LoadPrefDirElement.XLinkPos = TempInt;
11505  VecFile >> TempInt;
11506  LoadPrefDirElement.EXNumber = TempInt;
11507  VecFile >> TempInt;
11508  LoadPrefDirElement.CheckCount = TempInt;
11509  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
11510  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
11511  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
11512  if(!(LoadPrefDirElement.IsARoute))
11513  {
11514  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
11515  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
11516  }
11517  else
11518  {
11519  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
11520  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
11521  LoadPrefDirElement.PrefDirRoute);
11522  }
11523  StorePrefDirElement(0, LoadPrefDirElement);
11524  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
11525  }
11527  Utilities->CallLogPop(1509);
11528 }
11529 
11530 // ---------------------------------------------------------------------------
11531 
11532 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
11533 /*
11534  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
11535  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
11536 */
11537 {
11538  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
11539  int TempInt;
11540  int NumberOfPrefDirElements = 0;
11541 
11542  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
11543  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
11544  {
11545  Utilities->CallLogPop(1152);
11546  return false;
11547  }
11548  for(int x = 0; x < NumberOfPrefDirElements; x++)
11549  {
11550  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
11551  {
11552  Utilities->CallLogPop(1766);
11553  return false;
11554  }
11555  VecFile >> TempInt;
11556  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
11557  {
11558  Utilities->CallLogPop(163);
11559  return false;
11560  }
11561  VecFile >> TempInt;
11562  if((TempInt < -1) || (TempInt > 9)) // ELink
11563  {
11564  Utilities->CallLogPop(162);
11565  return false;
11566  }
11567  VecFile >> TempInt;
11568  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
11569  {
11570  Utilities->CallLogPop(164);
11571  return false;
11572  }
11573  VecFile >> TempInt;
11574  if((TempInt < -1) || (TempInt > 9)) // XLink
11575  {
11576  Utilities->CallLogPop(165);
11577  return false;
11578  }
11579  VecFile >> TempInt;
11580  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
11581  {
11582  Utilities->CallLogPop(166);
11583  return false;
11584  }
11585  VecFile >> TempInt;
11586  if((TempInt < -1) || (TempInt > 27)) // EXNumber
11587  {
11588  Utilities->CallLogPop(167);
11589  return false;
11590  }
11591  VecFile >> TempInt;
11592  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
11593  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
11594  // ELinkPos, XLink, XLinkPos & EXNumber
11595  {
11596  Utilities->CallLogPop(168);
11597  return false;
11598  }
11599  VecFile >> TempInt;
11600  if((TempInt != 0) && (TempInt != 1)) // RouteElement
11601  {
11602  Utilities->CallLogPop(1147);
11603  return false;
11604  }
11605  VecFile >> TempInt;
11606  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
11607  {
11608  Utilities->CallLogPop(1510);
11609  return false;
11610  }
11611  VecFile >> TempInt;
11612  if((TempInt != 0) && (TempInt != 1)) // PrefDirRoute
11613  {
11614  Utilities->CallLogPop(1148);
11615  return false;
11616  }
11617  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
11618  {
11619  Utilities->CallLogPop(1700);
11620  return false;
11621  }
11622  }
11623  Utilities->CallLogPop(169);
11624  return true;
11625 }
11626 
11627 // ---------------------------------------------------------------------------
11628 
11629 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
11630 {
11631  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
11632  int NumberOfPrefDirElements = PrefDirVector.size();
11633 
11634  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
11635  for(int y = 0; y < NumberOfPrefDirElements; y++)
11636  {
11637  VecFile << y << '\n'; // extra
11638  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n';
11639  VecFile << PrefDirVector.at(y).ELink << '\n';
11640  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
11641  VecFile << PrefDirVector.at(y).XLink << '\n';
11642  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
11643  VecFile << PrefDirVector.at(y).EXNumber << '\n';
11644  VecFile << PrefDirVector.at(y).CheckCount << '\n';
11645  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
11646  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
11647  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).PrefDirRoute);
11648  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
11649  {
11650  VecFile << "************" << '\0' << '\n'; // marker
11651  }
11652  else
11653  {
11654  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
11655  }
11656  }
11657  Utilities->CallLogPop(170);
11658 }
11659 
11660 // ---------------------------------------------------------------------------
11661 
11662 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
11663 {
11664  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
11665  int NumberOfSearchElements = SearchVector.size();
11666 
11667  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
11668  for(int y = 0; y < NumberOfSearchElements; y++)
11669  {
11670  VecFile << y << '\n'; // extra
11671  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
11672  VecFile << SearchVector.at(y).ELink << '\n';
11673  VecFile << SearchVector.at(y).ELinkPos << '\n';
11674  VecFile << SearchVector.at(y).XLink << '\n';
11675  VecFile << SearchVector.at(y).XLinkPos << '\n';
11676  VecFile << SearchVector.at(y).EXNumber << '\n';
11677  VecFile << SearchVector.at(y).CheckCount << '\n';
11678  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
11679  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
11680  Utilities->SaveFileBool(VecFile, SearchVector.at(y).PrefDirRoute);
11681  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
11682  {
11683  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
11684  }
11685  else
11686  {
11687  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
11688  }
11689  }
11690  Utilities->CallLogPop(1847);
11691 }
11692 
11693 // ---------------------------------------------------------------------------
11694 
11695 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
11696 /*
11697  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
11698  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
11699 */
11700 {
11701  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
11702  AnsiString(VLoc));
11703  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
11704 
11705  if(VecPos > -1)
11706  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
11707  else
11708  {
11709  Utilities->CallLogPop(171);
11710  return;
11711  }
11712  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
11713  if(VecPos > -1)
11714  ErasePrefDirElementAt(3, VecPos);
11715  else
11716  {
11717  Utilities->CallLogPop(172);
11718  return;
11719  }
11720  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
11721  if(VecPos > -1)
11722  ErasePrefDirElementAt(4, VecPos);
11723  else
11724  {
11725  Utilities->CallLogPop(173);
11726  return;
11727  }
11728  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
11729  if(VecPos > -1)
11730  ErasePrefDirElementAt(5, VecPos);
11731  else
11732  {
11733  Utilities->CallLogPop(174);
11734  return;
11735  }
11736  Utilities->CallLogPop(175);
11737 }
11738 
11739 // ---------------------------------------------------------------------------
11740 /*
11741  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
11742  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
11743 
11744  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
11745  in their place so that existing linkages will be preserved. At this stage this function is called to remove
11746  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
11747  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
11748  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
11749  PrefDirVector to correspond to the new track layout.
11750 
11751  {
11752  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
11753  if(PrefDirSize() == 0)
11754  {
11755  Utilities->CallLogPop(176);
11756  return;
11757  }
11758  for(int x=(PrefDirVector.size()-1);x>=0;x--)
11759  {
11760  int TV = PrefDirVector.at(x).TrackVectorPosition;
11761  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
11762  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
11763  if(Track->BlankElementAt(0, TV))
11764  {
11765  ErasePrefDirElementAt(6, x);
11766  }
11767  //if was a blankelement at x then ConnELink and ConnXLink both -1
11768  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
11769  {
11770  ErasePrefDirElementAt(7, x);
11771  }
11772  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
11773  //needs to be erased once, but if don't use 'else' then will erase two elements
11774  //since 'x' will correspond to the element after the first erased element
11775  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
11776  {
11777  ErasePrefDirElementAt(8, x);
11778  }
11779  }
11780  Utilities->CallLogPop(177);
11781  }
11782 */
11783 // ---------------------------------------------------------------------------
11784 
11785 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
11786 /*
11787  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
11788  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
11789 */
11790 {
11791  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
11792  bool AlreadyPresent, FoundFlag;
11793  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
11794 
11795  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
11796  {
11797  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
11798  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
11799  AlreadyPresent = false;
11800  if(FoundFlag)
11801  {
11802  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
11803  AlreadyPresent = true;
11804  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
11805  AlreadyPresent = true;
11806  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
11807  AlreadyPresent = true;
11808  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
11809  AlreadyPresent = true;
11810  }
11811  if(!AlreadyPresent)
11812  StorePrefDirElement(4, TempElement);
11813  }
11815  Utilities->CallLogPop(178);
11816 }
11817 /* earlier brute force search
11818  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
11819  {
11820  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
11821  bool AlreadyPresent = false;
11822  for(unsigned int y = 0;y<PrefDirSize();y++)
11823  {
11824  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
11825  }
11826  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
11827  }
11828 */
11829 
11830 // ---------------------------------------------------------------------------
11831 
11833 /*
11834  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
11835  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
11836  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
11837  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
11838  positions are likely to have changed, so this function is called to reset all the necessary connections and
11839  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
11840  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
11841  shouldn't have changed.
11842 */
11843 {
11844  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
11845  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11846  {
11847  bool FoundFlag;
11848  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
11849  if(FoundFlag)
11850  {
11851  PrefDirVector.at(x).TrackVectorPosition = VecPos;
11852  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
11853  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
11854  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
11855  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
11856  for(unsigned int z = 0; z < 4; z++)
11857  {
11858  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
11859  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
11860  }
11861  }
11862  else
11863  {
11864  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
11865  }
11866  }
11867  Utilities->CallLogPop(179);
11868 }
11869 
11870 // ---------------------------------------------------------------------------
11871 
11873 /*
11874  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
11875 */
11876 {
11877  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
11878  bool DiscrepancyFound = false;
11879 
11880  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11881  {
11882  bool FoundFlag;
11883  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
11884  if(FoundFlag)
11885  {
11886  TPrefDirElement PE = PrefDirVector.at(x);
11887  if(PE.TrackVectorPosition != VecPos)
11888  DiscrepancyFound = true;
11889  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
11890  {
11891  DiscrepancyFound = true;
11892  break;
11893  }
11894  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
11895  {
11896  DiscrepancyFound = true;
11897  break;
11898  }
11899  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
11900  {
11901  DiscrepancyFound = true;
11902  break;
11903  }
11904  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
11905  {
11906  DiscrepancyFound = true;
11907  break;
11908  }
11909  }
11910  else
11911  DiscrepancyFound = true;
11912  }
11913  if(DiscrepancyFound)
11914  {
11915  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
11916  ClearPrefDir(); // also clears multimap
11917  }
11918  Utilities->CallLogPop(1436);
11919 }
11920 
11921 // ---------------------------------------------------------------------------
11922 
11924 /*
11925  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
11926  return true for OK
11927 */
11928 {
11929  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
11930  bool DiscrepancyFound = false;
11931 
11932  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11933  {
11934  bool FoundFlag;
11935  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
11936  if(FoundFlag)
11937  {
11938  TPrefDirElement PE = PrefDirVector.at(x);
11939  if(PE.TrackVectorPosition != VecPos)
11940  DiscrepancyFound = true;
11941  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
11942  {
11943  DiscrepancyFound = true;
11944  break;
11945  }
11946  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
11947  {
11948  DiscrepancyFound = true;
11949  break;
11950  }
11951  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
11952  {
11953  DiscrepancyFound = true;
11954  break;
11955  }
11956  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
11957  {
11958  DiscrepancyFound = true;
11959  break;
11960  }
11961  }
11962  else
11963  DiscrepancyFound = true;
11964  }
11965  Utilities->CallLogPop(1512);
11966  return !DiscrepancyFound;
11967 }
11968 
11969 // ---------------------------------------------------------------------------
11970 
11971 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
11972 /*
11973  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
11974  turn and for the overall sizes.
11975 */
11976 {
11977  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
11978  bool FoundFlag = false;
11979  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
11980 
11981  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
11982  {
11983  TPrefDirElement CheckElement = PrefDirVector.at(a);
11984  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
11985  if(!FoundFlag)
11986  {
11987  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
11988  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
11989  }
11990  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
11991  {
11992  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
11993  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
11994  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
11995  }
11996  }
11997  if(PrefDirVector.size() != PrefDir4MultiMap.size())
11998  {
11999  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
12000  + " Caller=" + (AnsiString)Caller);
12001  }
12002  Utilities->CallLogPop(180);
12003 }
12004 
12005 // ---------------------------------------------------------------------------
12006 
12007 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
12008  int &PrefDirPos3)
12009 /*
12010  There are up to four elements at each H & V position in the PrefDirVector - two directions, and up to
12011  two tracks for 4-entry elements. This function retrieves all elements that are present at a give H & V
12012  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
12013  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
12014  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
12015 */
12016 {
12017  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
12018  AnsiString(VLoc));
12019  THVPair PrefDirMapKeyPair;
12020 
12021  PrefDirPos0 = -1;
12022  PrefDirPos1 = -1;
12023  PrefDirPos2 = -1;
12024  PrefDirPos3 = -1;
12025  FoundFlag = false;
12026  PrefDirMapKeyPair.first = HLoc;
12027  PrefDirMapKeyPair.second = VLoc;
12028  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
12029 
12030  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
12031  if(ItPair.first == ItPair.second)
12032  {
12033  Utilities->CallLogPop(181);
12034  return;
12035  }
12036  else
12037  {
12038  FoundFlag = true;
12039  PrefDirPos0 = ItPair.first->second;
12040  ItPair.first++;
12041  if(ItPair.first == ItPair.second)
12042  {
12043  Utilities->CallLogPop(182);
12044  return;
12045  }
12046  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
12047  PrefDirPos1 = ItPair.first->second;
12048  ItPair.first++;
12049  if(ItPair.first == ItPair.second)
12050  {
12051  Utilities->CallLogPop(183);
12052  return;
12053  }
12054  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
12055  PrefDirPos2 = ItPair.first->second;
12056  ItPair.first++;
12057  if(ItPair.first == ItPair.second)
12058  {
12059  Utilities->CallLogPop(184);
12060  return;
12061  }
12062  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
12063  PrefDirPos3 = ItPair.first->second;
12064  }
12065  Utilities->CallLogPop(185);
12066 }
12067 
12068 // ---------------------------------------------------------------------------
12069 
12070 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
12071 /*
12072  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
12073 */
12074 {
12075  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
12076  PrefDirVector.push_back(LoadPrefDirElement);
12077  THVPair PrefDir4MultiMapKeyPair;
12078  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
12079 
12080  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
12081  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
12082  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
12083  PrefDir4MultiMapEntry.second = LastElementNumber(68);
12084  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
12085 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
12086  Utilities->CallLogPop(186);
12087 }
12088 
12089 // ---------------------------------------------------------------------------
12090 
12091 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
12092 /*
12093  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
12094  4MultiMap if they are greater than the erased value.
12095 */
12096 {
12097  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
12098  bool FoundFlag;
12099 
12100  if(!PrefDirVector.empty())
12101  {
12102  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
12103  if(!FoundFlag)
12104  {
12105  throw Exception("Failed to find PrefDir4MultiMap erase element");
12106  }
12107  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
12108  PrefDir4MultiMap.erase(EraseIt);
12109  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
12111  }
12112  Utilities->CallLogPop(187);
12113 }
12114 
12115 // ---------------------------------------------------------------------------
12116 
12117 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
12118 /*
12119  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
12120  4MultiMap if they are greater than the erased value.
12121 */
12122 {
12123  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
12124  AnsiString(ErasedElementNumber));
12125  if(!PrefDir4MultiMap.empty())
12126  {
12127  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
12128  {
12129  if(MapPtr->second > ErasedElementNumber)
12130  MapPtr->second--;
12131  }
12132  }
12133  Utilities->CallLogPop(1450);
12134 }
12135 
12136 // ---------------------------------------------------------------------------
12137 
12138 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
12139 /*
12140  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
12141  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
12142  nothing is found this is an error but the error message is given in the calling function.
12143 */
12144 {
12145  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
12146  FoundFlag = false;
12147  if(PrefDirVectorPosition >= PrefDirVector.size())
12148  {
12149  throw Exception("PrefDirVectorPosition out of range");
12150  }
12151  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
12152  THVPair PrefDir4MultiMapKeyPair;
12153 
12154  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
12155  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
12156  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
12157 
12158  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
12159  if(ItPair.first == ItPair.second)
12160  {
12161  Utilities->CallLogPop(188);
12162  return ItPair.first; // nothing found but have to return an iterator, FoundFlag indicates nothing found
12163  }
12164  else
12165  {
12166  if(ItPair.first->second == PrefDirVectorPosition)
12167  {
12168  FoundFlag = true;
12169  Utilities->CallLogPop(189);
12170  return ItPair.first;
12171  }
12172  ItPair.first++;
12173  if(ItPair.first == ItPair.second)
12174  {
12175  Utilities->CallLogPop(190);
12176  return ItPair.first; // nothing found
12177  }
12178  if(ItPair.first->second == PrefDirVectorPosition)
12179  {
12180  FoundFlag = true;
12181  Utilities->CallLogPop(191);
12182  return ItPair.first;
12183  }
12184  ItPair.first++;
12185  if(ItPair.first == ItPair.second)
12186  {
12187  Utilities->CallLogPop(192);
12188  return ItPair.first; // nothing found
12189  }
12190  if(ItPair.first->second == PrefDirVectorPosition)
12191  {
12192  FoundFlag = true;
12193  Utilities->CallLogPop(193);
12194  return ItPair.first;
12195  }
12196  ItPair.first++;
12197  if(ItPair.first == ItPair.second)
12198  {
12199  Utilities->CallLogPop(194);
12200  return ItPair.first; // nothing found
12201  }
12202  if(ItPair.first->second == PrefDirVectorPosition)
12203  {
12204  FoundFlag = true;
12205  Utilities->CallLogPop(195);
12206  return ItPair.first;
12207  }
12208  }
12209  Utilities->CallLogPop(196);
12210  return ItPair.first; // nothing found
12211 }
12212 
12213 // ---------------------------------------------------------------------------
12214 
12215 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
12216 /*
12217  Although there may be up to four entries at one H & V position this function gets just one. It is
12218  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
12219  at H & V.
12220 */
12221 {
12222  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12223  THVPair PrefDir4MultiMapKeyPair;
12224 
12225  PrefDir4MultiMapKeyPair.first = HLoc;
12226  PrefDir4MultiMapKeyPair.second = VLoc;
12227  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
12228 
12229  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
12230  if(ItPair.first == ItPair.second) // nothing found
12231  {
12232  Utilities->CallLogPop(197);
12233  return -1;
12234  }
12235  else
12236  {
12237  Utilities->CallLogPop(198);
12238  return ItPair.first->second;
12239  }
12240 }
12241 
12242 // ---------------------------------------------------------------------------
12243 
12244 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
12245 {
12246  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
12247  bool ErasedFlag = false;
12248 
12249  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
12250  {
12251  if(PrefDirSize() == 0)
12252  {
12253  Utilities->CallLogPop(1511);
12254  return;
12255  }
12256  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
12257  {
12258  ErasedFlag = false;
12259  // use 'else' to ensure don't try to access an erased element
12260  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
12261  {
12262  ErasePrefDirElementAt(11, x);
12263  ErasedFlag = true;
12264  }
12265  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
12266  {
12267  ErasePrefDirElementAt(12, x);
12268  ErasedFlag = true;
12269  }
12270  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
12271  {
12272  ErasePrefDirElementAt(13, x);
12273  ErasedFlag = true;
12274  }
12275  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
12276  {
12277  ErasePrefDirElementAt(9, x);
12278  ErasedFlag = true;
12279  }
12280  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
12281  {
12282  ErasePrefDirElementAt(10, x);
12283  ErasedFlag = true;
12284  }
12285  if(!ErasedFlag)
12286  {
12287  // don't use 'else' here as may be more than one that need decrementing
12288  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
12289  {
12290  PrefDirVector.at(x).TrackVectorPosition--;
12291  }
12292  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
12293  {
12294  PrefDirVector.at(x).Conn[0]--;
12295  }
12296  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
12297  {
12298  PrefDirVector.at(x).Conn[1]--;
12299  }
12300  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
12301  {
12302  PrefDirVector.at(x).Conn[2]--;
12303  }
12304  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
12305  {
12306  PrefDirVector.at(x).Conn[3]--;
12307  }
12308  }
12309  }
12310  }
12311  Utilities->CallLogPop(1434);
12312 }
12313 
12314 // ---------------------------------------------------------------------------
12315 
12316 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
12317 {
12318  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
12319  OverallDistance = 0;
12320  OverallSpeedLimit = 0;
12321  LeadingPointsAtLastElement = false;
12322  if(PrefDirSize() == 0) // shouldn't be empty when this called
12323  {
12324  Utilities->CallLogPop(1491);
12325  return;
12326  }
12327 
12328  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
12329  {
12330  LeadingPointsAtLastElement = true;
12331  Utilities->CallLogPop(1492);
12332  return;
12333  }
12334  for(unsigned int x = 0; x < PrefDirSize(); x++)
12335  {
12336  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
12337  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
12338  {
12339  OverallDistance += PrefDirElement.Length23;
12340  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
12341  {
12342  if(x == 0)
12343  {
12344  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
12345  }
12346  else
12347  {
12348  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
12349  {
12350  OverallSpeedLimit = -1;
12351  }
12352  }
12353  }
12354  }
12355  else
12356  {
12357  OverallDistance += PrefDirElement.Length01;
12358  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
12359  {
12360  if(x == 0)
12361  {
12362  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
12363  }
12364  else
12365  {
12366  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
12367  {
12368  OverallSpeedLimit = -1;
12369  }
12370  }
12371  }
12372  }
12373  }
12374  Utilities->CallLogPop(1529);
12375 }
12376 
12377 // ---------------------------------------------------------------------------
12378 
12379 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
12380 {
12381  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
12382  if(PrefDirSize() == 0)
12383  {
12384  Utilities->CallLogPop(1564);
12385  return;
12386  }
12387 
12388  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12389  bool FoundFlag;
12391  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
12392 
12393  while(MMIT != PrefDir4MultiMap.end())
12394  {
12395  HLoc = MMIT->first.first;
12396  VLoc = MMIT->first.second;
12397  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12398  H = HLoc - Track->GetHLocMin();
12399  V = VLoc - Track->GetVLocMin();
12400  // always found in order, any missing have PrefDirPosx == -1
12401  if(PrefDirPos0 > -1)
12402  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
12403  if(PrefDirPos1 > -1)
12404  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
12405  if(PrefDirPos2 > -1)
12406  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
12407  if(PrefDirPos3 > -1)
12408  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
12409  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
12410  { // need to plot all 4 in order to obtain all the direction graphics
12411  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12412  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12413  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12414  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12415  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12416  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12417  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
12418  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
12419  MMIT++;
12420  MMIT++;
12421  MMIT++;
12422  MMIT++;
12423  }
12424  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
12425  {
12426  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12427  { // 0 & 1 constitute the bidirectional PrefDir
12428  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12429  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12430  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12431  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12432  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
12433  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
12434  MMIT++;
12435  MMIT++;
12436  MMIT++;
12437  }
12438  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
12439  { // 0 & 2 constitute the bidirectional PrefDir
12440  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12441  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12442  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12443  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12444  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12445  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12446  MMIT++;
12447  MMIT++;
12448  MMIT++;
12449  }
12450  else
12451  { // 1 & 2 constitute the bidirectional PrefDir
12452  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12453  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12454  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12455  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12456  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12457  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12458  MMIT++;
12459  MMIT++;
12460  MMIT++;
12461  }
12462  }
12463  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
12464  {
12465  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12466  { // 0 & 1 constitute the bidirectional PrefDir
12467  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12468  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12469  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12470  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12471  MMIT++;
12472  MMIT++;
12473  }
12474  else
12475  { // 2 unidirectional PrefDirs
12476  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12477  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12478  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12479  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12480  MMIT++;
12481  MMIT++;
12482  }
12483  }
12484  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
12485  {
12486  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12487  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12488  MMIT++;
12489  }
12490  }
12491  Utilities->CallLogPop(1565);
12492 }
12493 
12494 // ---------------------------------------------------------------------------
12495 
12496 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
12497 /*
12498  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
12499  level crossing, signals with wrong direction set, or buffers.
12500 */
12501 {
12502  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
12503  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12504  bool FoundFlag;
12506  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
12507 
12508  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
12509  ElementIn.VLoc)))
12510  {
12511  Utilities->CallLogPop(1982);
12512  return false;
12513  }
12514  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at exit end
12515  {
12516  Utilities->CallLogPop(1983);
12517  return false;
12518  }
12519  if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal))
12520  {
12521  Utilities->CallLogPop(1995);
12522  return false;
12523  }
12524 // Now check that there is only a single prefdir set
12525  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12526 // always found in order, any missing have PrefDirPosx == -1
12527  if(PrefDirPos0 > -1)
12528  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
12529  if(PrefDirPos1 > -1)
12530  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
12531  if(PrefDirPos2 > -1)
12532  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
12533  if(PrefDirPos3 > -1)
12534  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
12535 
12536  if(PrefDirPos3 > -1) // 4 found, all bidirectional
12537  {
12538  Utilities->CallLogPop(1984);
12539  return false;
12540  }
12541  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
12542  {
12543  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
12544  {
12545  Utilities->CallLogPop(1985);
12546  return false;
12547  }
12548  else
12549  {
12550  Utilities->CallLogPop(1986);
12551  return true;
12552  }
12553  }
12554  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
12555  {
12556  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
12557  {
12558  Utilities->CallLogPop(1987);
12559  return false;
12560  }
12561  else
12562  {
12563  Utilities->CallLogPop(1988);
12564  return true;
12565  }
12566  }
12567  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
12568  {
12569  if(PrefDirElement0.XLinkPos == EntryPos)
12570  {
12571  Utilities->CallLogPop(1989);
12572  return false;
12573  }
12574  else
12575  {
12576  Utilities->CallLogPop(1990);
12577  return true;
12578  }
12579  }
12580  else
12581  {
12582  Utilities->CallLogPop(1991);
12583  return false; // none found
12584  }
12585 }
12586 
12587 // ---------------------------------------------------------------------------
12588 
12590 {
12591 /* //Added at v2.1.0
12592  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
12593  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
12594  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
12595  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
12596  and can be modelled better anyway.
12597 
12598  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
12599  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
12600  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
12601  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
12602  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
12603  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
12604 */
12605  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
12606  ElementIn.VLoc + "," + XLink);
12607  int TrackVecPos;
12608  bool TrackFoundFlag;
12609  TTrackElement TempTrackElement;
12610 
12611  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
12612  {
12613  Utilities->CallLogPop(2047);
12614  return false;
12615  }
12616 
12617 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
12618  if(XLink == 1)
12619  {
12620  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
12621  if(TrackFoundFlag)
12622  {
12623  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
12624  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
12625  {
12626  Utilities->CallLogPop(2048);
12627  return true;
12628  }
12629  }
12630  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
12631  if(TrackFoundFlag)
12632  {
12633  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
12634  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
12635  {
12636  Utilities->CallLogPop(2049);
12637  return true;
12638  }
12639  }
12640  }
12641 
12642 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
12643  if(XLink == 3)
12644  {
12645  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
12646  if(TrackFoundFlag)
12647  {
12648  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
12649  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
12650  {
12651  Utilities->CallLogPop(2050);
12652  return true;
12653  }
12654  }
12655  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
12656  if(TrackFoundFlag)
12657  {
12658  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
12659  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
12660  {
12661  Utilities->CallLogPop(2051);
12662  return true;
12663  }
12664  }
12665  }
12666 
12667 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
12668  if(XLink == 7)
12669  {
12670  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
12671  if(TrackFoundFlag)
12672  {
12673  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
12674  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
12675  {
12676  Utilities->CallLogPop(2052);
12677  return true;
12678  }
12679  }
12680  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
12681  if(TrackFoundFlag)
12682  {
12683  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
12684  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
12685  {
12686  Utilities->CallLogPop(2053);
12687  return true;
12688  }
12689  }
12690  }
12691 
12692 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
12693  if(XLink == 9)
12694  {
12695  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
12696  if(TrackFoundFlag)
12697  {
12698  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
12699  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
12700  {
12701  Utilities->CallLogPop(2054);
12702  return true;
12703  }
12704  }
12705  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
12706  if(TrackFoundFlag)
12707  {
12708  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
12709  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
12710  {
12711  Utilities->CallLogPop(2055);
12712  return true;
12713  }
12714  }
12715  }
12716  Utilities->CallLogPop(2056);
12717  return false;
12718 }
12719 
12720 // ---------------------------------------------------------------------------
12721 
12722 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
12723 {
12724 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
12725  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
12726  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
12727  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
12728  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
12729 */
12730  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
12732  bool FoundFlag, ContFlag, FoundElements = false;
12733  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12734  TPrefDirElement NextElement;
12735 
12736  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
12737  {
12738  LastIteratorValue++;
12739  ContFlag = false;
12740  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
12741  continue;
12742  if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal))
12743  continue;
12744 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
12745  // found a potential route start point
12746  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
12747  {
12748  continue;
12749  }
12750  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
12751  {
12752  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
12753  if(PDVIt->TrackType == Continuation)
12754  {
12755  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
12756  {
12757  continue;
12758  }
12759  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
12760  {
12761  continue;
12762  }
12763  }
12764  StartElement = *PDVIt;
12765 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
12766  // diverging track on which there was no pref dir. See below for 2 required changes.
12767  }
12768  else
12769  {
12770  continue;
12771  }
12772  // now track along until find a signal or continuation, checking validity for each element
12773  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
12774  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
12775  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12776  if(PrefDirPos0 == -1) // no continuing prefdir
12777  {
12778  continue;
12779  }
12780  bool NextElementFoundFlag = false;
12781  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
12782  {
12783  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
12784  NextElementFoundFlag = true;
12785  }
12786  if(PrefDirPos1 > -1)
12787  {
12788  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
12789  {
12790  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
12791  NextElementFoundFlag = true;
12792  }
12793  }
12794  if(PrefDirPos2 > -1)
12795  {
12796  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
12797  {
12798  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
12799  NextElementFoundFlag = true;
12800  }
12801  }
12802  if(PrefDirPos3 > -1)
12803  {
12804  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
12805  {
12806  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
12807  NextElementFoundFlag = true;
12808  }
12809  }
12810  if(!NextElementFoundFlag)
12811  {
12812  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
12813 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
12814  }
12815  while(true)
12816  {
12817  // check validity
12818  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
12819  {
12820  ContFlag = true;
12821  break;
12822  }
12823  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
12824  {
12825  ContFlag = true;
12826  break;
12827  }
12828  // check if in a route, providing not a signal, as a signal might be at the start of a route
12829  if(NextElement.TrackType != SignalPost)
12830  {
12831  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
12832  {
12833  ContFlag = true;
12834  break;
12835  }
12836  }
12837  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
12838  // can't be a gound signal as would have failed the validity test
12839  {
12840  EndElement = NextElement;
12841  break;
12842  }
12843  // get the next element in the sequence
12844  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
12845  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
12846  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12847  if(PrefDirPos0 == -1) // no continuing prefdir
12848  {
12849  ContFlag = true;
12850  break;
12851  }
12852  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
12853  {
12854  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
12855  continue;
12856  }
12857  if(PrefDirPos1 > -1)
12858  {
12859  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
12860  {
12861  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
12862  continue;
12863  }
12864  }
12865  if(PrefDirPos2 > -1)
12866  {
12867  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
12868  {
12869  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
12870  continue;
12871  }
12872  }
12873  if(PrefDirPos3 > -1)
12874  {
12875  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
12876  {
12877  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
12878  continue;
12879  }
12880  }
12881  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
12882  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
12883  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
12884  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
12885  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
12886  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
12887  {
12888  ContFlag = true;
12889  break;
12890  }
12891  else
12892  {
12893  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
12894  // could drop the bridge test but keep it to show the change history
12895  break;
12896 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
12897  }
12898  }
12899  if(ContFlag)
12900  continue;
12901  // else have start and end elements set & all elements valid, so set up the route segment
12902  FoundElements = true;
12903  break;
12904  }
12905  if(FoundElements)
12906  {
12907  Utilities->CallLogPop(1992);
12908  return true;
12909  }
12910  else
12911  {
12912  Utilities->CallLogPop(1993);
12913  return false;
12914  }
12915 }
12916 
12917 // ---------------------------------------------------------------------------
12918 // TOneRoute
12919 // ---------------------------------------------------------------------------
12920 
12921 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
12922 {
12923 /* General:
12924  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
12925  containing all the new elements to form the route. When complete, the SearchVector is converted into route
12926  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
12927  route will use automatic signals or not.
12928  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
12929  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
12930  elements, so additional work is needed to complete all their members before they are ready for conversion into
12931  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
12932  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
12933  ConvertAndAdd.......
12934 */
12935  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
12936  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
12937  ClearRoute();
12938  int TrackVectorPosition;
12939  TTrackElement TrackElement;
12940  TPrefDirElement FirstElement, LastElement;
12941 
12942  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
12943  {
12944  Utilities->CallLogPop(199);
12945  return false;
12946  }
12947  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
12948  {
12949  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
12950  Utilities->CallLogPop(1996);
12951  return false;
12952  }
12953  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
12954  {
12955  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation");
12956  Utilities->CallLogPop(200);
12957  return false;
12958  }
12959 
12960  if(Track->IsLCAtHV(18, HLoc, VLoc))
12961  {
12962  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
12963  Utilities->CallLogPop(1909);
12964  return false;
12965  }
12966 
12967 // check if selected a train & disallow if so
12968  if(TrackElement.TrainIDOnElement > -1)
12969  {
12970  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
12971  Utilities->CallLogPop(202);
12972  return false;
12973  }
12974 
12975 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
12976  TPrefDirElement PrefDirElement;
12977  int LockedVectorNumber;
12978 
12979  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
12980  {
12981  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
12982  Utilities->CallLogPop(203);
12983  return false;
12984  }
12985  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
12986  {
12987  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
12988  Utilities->CallLogPop(204);
12989  return false;
12990  }
12991 
12993  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
12994 // signal in an autosig route & follow with a non-autosig route
12995 
12996  TPrefDirElement BlankElement;
12997 
12998  StartElement1 = BlankElement;
12999  StartElement2 = BlankElement; //not used in this routine but used in GetNextPreferred.... though could probably dispense with it there
13000 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
13001  bool InPrefDirFlag = false;
13002 
13003  bool FoundFlag;
13004  int PrefDirPos0 = -1;
13005  int PrefDirPos1 = -1;
13006  int PrefDirPos2 = -1;
13007  int PrefDirPos3 = -1;
13008 
13010  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13011  int PrefDirVecPos[4] =
13012  {PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3};
13013 
13014  for(int x = 0; x < 4; x++)
13015  {
13016  int b = PrefDirVecPos[x];
13017  if(b > -1)
13018  {
13019  // only allow the appropriate exit route to be searched
13020  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
13021  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
13022  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
13023  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
13024  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
13025  {
13026  InPrefDirFlag = true;
13027  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
13028  if(AutoSigsFlag)
13029  {
13030  StartElement1.AutoSignals = true;
13031  }
13032  StartElement1.PrefDirRoute = true;
13033  }
13034  }
13035  }
13036 
13037  if(!InPrefDirFlag)
13038  {
13040  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
13041  Utilities->CallLogPop(205);
13042  return false;
13043  }
13044 
13045 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
13047  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
13048 
13049  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
13050  {
13051  throw Exception("Selection in two routes - should never happen!");
13052  }
13053 
13054  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
13055  {
13056  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
13057  {
13058  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
13059  Utilities->CallLogPop(206);
13060  return false;
13061  }
13062  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
13063  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
13064  {
13065  TrainController->StopTTClockMessage(14, "No forward connection from this position");
13066  Utilities->CallLogPop(207);
13067  return false;
13068  }
13069  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
13070  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
13071  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
13072  {
13073  TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
13074  Utilities->CallLogPop(208);
13075  return false;
13076  }
13077  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
13079  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
13080  if(AutoSigsFlag)
13081  {
13082  StartElement1.AutoSignals = true;
13083  }
13084  StartElement1.PrefDirRoute = true;
13086  Utilities->CallLogPop(209);
13087  return true; // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
13088  }
13089 
13090  else // no route started
13091  {
13092 // check if selected position is adjacent to start or end of an existing route and disallow
13093  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
13094  {
13095  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
13096  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
13097  {
13098  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
13099  Utilities->CallLogPop(210);
13100  return false;
13101  }
13102  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
13103  {
13104  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
13105  Utilities->CallLogPop(211);
13106  return false;
13107  }
13108  }
13109 
13110 // check if it's adjacent to end of an an existing route,
13111  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
13112  {
13114  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
13115  {
13116  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
13117  Utilities->CallLogPop(212);
13118  return false;
13119  }
13120  }
13121  SearchVector.push_back(StartElement1);
13122  Utilities->CallLogPop(213);
13123  return true;
13124  }
13125 }
13126 
13127 // ---------------------------------------------------------------------------
13128 
13129 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag,
13130  IDInt &ReqPosRouteID, bool &PointsChanged)
13131 
13132 /*
13133  Return true if select valid next element, in which case the route is set & stored in SearchVector. Return false for an invalid next element.
13134 
13135  Declare integers EndPosition (the position used) and ReqPosRouteID to hold (when required) the existing route selected (for linking to an existing route),
13136  this being set to -1 for not used.
13137  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
13138  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
13139  Check correct type of element - signal/buffers/continuation.
13140  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
13141  EndElement2 corresponding to the 2 possible PrefDir elements).
13142  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
13143  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
13144  linked forward to another route.
13145  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
13146  for same position as start should cover this)
13147 
13148  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
13149  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
13150  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
13151  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
13152  If the search fails then return false.
13153  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
13154  in the SearchVector to ensure it's entered as part of the new route.
13155  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
13156  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
13157  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed
13158  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
13159  so return false, with an appropriate message if ConsecSignalsRoute set.
13160 */
13161 
13162 {
13163  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
13164  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignals) + "," + AnsiString((short)AutoSigsFlag));
13165  int EndPosition; // the position selected
13166 
13167  Track->LCFoundInAutoSigsRoute = false;
13169  TotalSearchCount = 0;
13170  ReqPosRouteID = IDInt(-1); // default value for not used
13171  TTrackElement TrackElement;
13172  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
13173  // given element as can't select 2-track elements
13174  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
13175  {
13176  Utilities->CallLogPop(214);
13177  return false;
13178  }
13179 
13180  if(Track->IsLCAtHV(19, HLoc, VLoc))
13181  {
13182  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
13183  Utilities->CallLogPop(1908);
13184  return false;
13185  }
13186 
13187 // cancel selection if on original start element
13188  if(EndPosition == StartRoutePosition)
13189  {
13190  Utilities->CallLogPop(215);
13191  return false;
13192  }
13193  if(AutoSigsFlag)
13194  {
13195  if(TrackElement.TrackType == Buffers)
13196  {
13197  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
13198  Utilities->CallLogPop(216);
13199  return false;
13200  }
13201  }
13202  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
13203  {
13204  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
13205  Utilities->CallLogPop(217);
13206  return false;
13207  }
13208 
13209 // check if train on element
13210  if(TrackElement.TrainIDOnElement > -1)
13211  {
13212  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
13213  Utilities->CallLogPop(219);
13214  return false;
13215  }
13216 
13217 // disallow if not in EveryPrefDir & set EndElement(s)
13218  bool InPrefDirFlag = false;
13219 
13220  bool FoundFlag;
13221  int PrefDirPos0 = -1;
13222  int PrefDirPos1 = -1;
13223  int PrefDirPos2 = -1;
13224  int PrefDirPos3 = -1;
13225 
13226  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
13227  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13228  int PrefDirVecPos[4] =
13229  {PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3};
13230 
13231  for(int x = 0; x < 4; x++)
13232  {
13233  int b = PrefDirVecPos[x];
13234  if(b > -1)
13235  {
13236  InPrefDirFlag = true;
13237  if(EndElement1.TrackVectorPosition == -1)
13238  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
13239  else
13240  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
13241  }
13242  }
13243  if(!InPrefDirFlag)
13244  {
13246  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
13247  Utilities->CallLogPop(220);
13248  return false;
13249  }
13250 
13251 // check if in an existing route - can't be a bridge so can use a simple 'find'
13252 // bool InRoute = false;
13254  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
13255 
13256  if(RoutePair.first > -1)
13257  {
13258  if(RoutePair.second != 0) // not first element in existing route so no good
13259  {
13260  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
13261  Utilities->CallLogPop(221);
13262  return false;
13263  }
13264  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
13265 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
13266  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
13267  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
13268  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
13269  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
13270  {
13271  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
13272  Utilities->CallLogPop(222);
13273  return false;
13274  }
13275  EndElement1 = RouteElement;
13276  EndElement2 = BlankElement; // only need the route element
13277  EndPosition = EndElement1.TrackVectorPosition;
13278  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
13279  }
13280 
13281 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
13282 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
13283 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
13284 
13285  if(EndElement1.HLoc >= StartElement1.HLoc)
13286  {
13288  SearchLimitHighH = EndElement1.HLoc + 15;
13289  }
13290  else
13291  {
13292  SearchLimitLowH = EndElement1.HLoc - 15;
13294  }
13295 
13296  if(EndElement1.VLoc >= StartElement1.VLoc)
13297  {
13299  SearchLimitHighV = EndElement1.VLoc + 15;
13300  }
13301  else
13302  {
13303  SearchLimitLowV = EndElement1.VLoc - 15;
13305  }
13306 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
13307  check & TotalSearchCounts check
13308  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
13309  {
13310  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
13311  Utilities->CallLogPop(1693);
13312  return false;
13313  }
13314 */
13315 // check if adjacent to start and disallow
13316  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
13317  {
13319  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
13320 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
13321 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
13322  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
13323  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
13324  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
13325  {
13326  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
13327  Utilities->CallLogPop(223);
13328  return false;
13329  }
13330 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
13331 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
13332  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
13333  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
13334  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
13335  {
13336  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
13337  Utilities->CallLogPop(224);
13338  return false;
13339  }
13340 
13341 // check if adjacent to end of a route & disallow
13343  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
13344  {
13345  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
13346  Utilities->CallLogPop(225);
13347  return false;
13348  }
13349  }
13350 
13351 // check for same route as start element
13353  {
13354  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
13355  Utilities->CallLogPop(226);
13356  return false;
13357  }
13358 
13359 // check for a looping route
13360  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
13361  {
13363  {
13364  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
13365  Utilities->CallLogPop(1844);
13366  return false;
13367  }
13368  }
13369 
13370 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
13371 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
13372 // and don't want to add it again
13373  if(StartSelectionRouteID > -1)
13374  {
13375  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
13376  AutoSigsFlag))
13377  {
13378  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
13379  if(PointsToBeChanged(5))
13380  {
13381  PointsChanged = true;
13382  }
13383  Utilities->CallLogPop(227);
13384  return true;
13385  }
13386  else if(!Track->SuppressRouteFailMessage)
13387  { //corrected at v2.7.0 - brackets were missed earlier so if SearchForPreferredRoute failed & else condition failed too then returned false with no message
13389  Utilities->CallLogPop(228);
13390  return false;
13391  }
13392  }
13393  else
13394  {
13395 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
13396 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
13397 
13398 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
13399 // note that a blank element will have XLinkPos set to -1
13400  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
13401  {
13402  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
13403  AutoSigsFlag))
13404  {
13405  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
13406  if(PointsToBeChanged(6))
13407  {
13408  PointsChanged = true;
13409  }
13410  Utilities->CallLogPop(229);
13411  return true;
13412  }
13413  else
13414  {
13417  Utilities->CallLogPop(230);
13418  return false;
13419  }
13420  }
13421  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
13422  {
13423  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
13424  AutoSigsFlag))
13425  {
13426  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
13427  if(PointsToBeChanged(7))
13428  {
13429  PointsChanged = true;
13430  }
13431  Utilities->CallLogPop(231);
13432  return true;
13433  }
13434  else
13435  {
13438  Utilities->CallLogPop(232);
13439  return false;
13440  }
13441  }
13442 
13443  // now start off in the best direction
13444  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
13445  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
13446  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
13447  // unless new problems are found.
13448  if(StartElement1.XLinkPos == BestPos)
13449  {
13450  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
13451  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
13452  AutoSigsFlag))
13453  {
13454  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
13455  if(PointsToBeChanged(8))
13456  {
13457  PointsChanged = true;
13458  }
13459  Utilities->CallLogPop(233);
13460  return true;
13461  }
13462  else if(StartElement2.TrackVectorPosition > -1)
13463  {
13464  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
13465  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
13466  AutoSigsFlag))
13467  {
13468  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
13469  if(PointsToBeChanged(9))
13470  {
13471  PointsChanged = true;
13472  }
13473  Utilities->CallLogPop(234);
13474  return true;
13475  }
13476  }
13477  }
13478  else if(StartElement2.TrackVectorPosition > -1)
13479  {
13480  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
13481  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
13482  AutoSigsFlag))
13483  {
13484  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
13485  if(PointsToBeChanged(10));
13486  {
13487  PointsChanged = true;
13488  }
13489  Utilities->CallLogPop(1857);
13490  return true;
13491  }
13492  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
13493  AutoSigsFlag))
13494  {
13495  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
13496  if(PointsToBeChanged(11));
13497  {
13498  PointsChanged = true;
13499  }
13500  Utilities->CallLogPop(1858);
13501  return true;
13502  }
13503  }
13504  else if(StartElement1.XLinkPos == (1 - BestPos))
13505  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction)
13506  {
13507  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
13508  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
13509  AutoSigsFlag))
13510  {
13511  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
13512  if(PointsToBeChanged(12))
13513  {
13514  PointsChanged = true;
13515  }
13516  Utilities->CallLogPop(1864);
13517  return true;
13518  }
13519  }
13520  }
13523  Utilities->CallLogPop(235);
13524  return false;
13525 }
13526 
13527 // ---------------------------------------------------------------------------
13528 
13529 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
13530 {
13531  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
13532  if(PrefDirSize() == 0)
13533  {
13534  Utilities->CallLogPop(1704);
13535  return;
13536  }
13537  for(unsigned int x = 0; x < PrefDirSize(); x++)
13538  {
13539  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
13540  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
13541  {
13542  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
13543  TempPrefDirElement.EXGraphicPtr);
13544  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
13545  {
13546  if(x == 0)
13547  {
13548  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
13549  TempPrefDirElement.EntryDirectionGraphicPtr);
13550  }
13551  if(x == (PrefDirSize() - 1))
13552  {
13553  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
13554  TempPrefDirElement.EntryDirectionGraphicPtr);
13555  }
13556  }
13557  }
13558  }
13559 
13560  Utilities->CallLogPop(1705);
13561 }
13562 
13563 // ---------------------------------------------------------------------------
13564 
13565 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
13566  TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndPosition, bool AutoSigsFlag)
13567 
13568 /*
13569  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
13570  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If it's an
13571  element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
13572  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
13573  Return false if any element (apart from RequiredPosition) is on an existing route.
13574  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point in a recursive call - see later).
13575 
13576  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
13577  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
13578  added during the function so as to leave it exactly as it was on entering, then return false).
13579  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
13580  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
13581  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
13582  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
13583  the route number that the searched-for element is the start of if any, and set to -1 if no
13584  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
13585  this unit, together with the ConsecSignalsRoute and AutoSigsFlag flags.
13586  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
13587  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
13588 
13589  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
13590  or a continuation, and fail if so. Check if reached a valid next signal in ConsecSignalsRoute on any but firstpass
13591  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
13592  for recursive calls), and fail if so as user should always select the next signal in a route if ConsecSignals set.
13593  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
13594  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
13595  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
13596  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
13597  or if train on element (unless a bridge & train on different track).
13598  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
13599  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
13600  a leading point where both trailing directions are in EveryPrefDir, if not fail.
13601  Check if found RequiredPosition & that it's a signal/buffer/continuation. If OK save in SearchVector with
13602  AutoSignals member set if AutoSigsFlag set, then return true.
13603  Check & fail if a buffer or continuation (unless it is the RequiredPosition, in which case will have succeeded in the above check).
13604 
13605  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
13606  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
13607  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
13608  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
13609  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
13610  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
13611  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
13612 
13613  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
13614  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
13615 */
13616 
13617 {
13618  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
13619  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
13620  AnsiString((short)AutoSigsFlag));
13621  int VectorCount = 0;
13622  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
13623 
13624 // check for a fouled diagonal for first element. Added for v1.3.2
13625  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
13626  {
13627  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
13628  {
13629  for(int x = 0; x < VectorCount; x++)
13630  SearchVector.erase(SearchVector.end() - 1);
13631  Utilities->CallLogPop(2043);
13632  return false;
13633  }
13634  }
13635 
13636  bool FirstPass = true;
13637 
13638  while(true)
13639  {
13640  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
13641  {
13642  Track->LCFoundInAutoSigsRoute = true;
13643  }
13644  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
13645  {
13646  for(int x = 0; x < VectorCount; x++)
13647  SearchVector.erase(SearchVector.end() - 1);
13648  Utilities->CallLogPop(1926);
13649  return false;
13650  }
13651  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
13652  {
13653  for(int x = 0; x < VectorCount; x++)
13654  SearchVector.erase(SearchVector.end() - 1);
13655  Utilities->CallLogPop(236);
13656  return false;
13657  }
13658  if(!FirstPass && ConsecSignals && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
13659  // reached a valid signal that isn't the required position, user should always select the next
13660  // signal in a route so have to fail
13661  // won't affect recurive searches as for them the first pass element is always a point
13662  {
13663  for(int x = 0; x < VectorCount; x++)
13664  SearchVector.erase(SearchVector.end() - 1);
13665  Utilities->CallLogPop(237);
13666  return false;
13667  }
13668  FirstPass = false;
13669  int NextPosition = PrefDirElement.Conn[XLinkPos];
13670  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
13671  TPrefDirElement SearchElement(NextTrackElement);
13672  SearchElement.TrackVectorPosition = NextPosition;
13673  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
13674  SearchElement.ELinkPos = NextELinkPos;
13675  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
13676  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
13677  int NextXLinkPos;
13678  if(SearchElement.ELinkPos == 0)
13679  NextXLinkPos = 1;
13680  if(SearchElement.ELinkPos == 1)
13681  NextXLinkPos = 0;
13682  if(SearchElement.ELinkPos == 2)
13683  NextXLinkPos = 3;
13684  if(SearchElement.ELinkPos == 3)
13685  NextXLinkPos = 2;
13686  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
13687  {
13688  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
13689 // note that may be buffers, continuation or gap
13690  SearchElement.XLinkPos = NextXLinkPos;
13691  }
13692 // can't set XLink or XLinkPos yet if the element is a leading point.
13693 
13694 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
13695  for(unsigned int x = 0; x < SearchVector.size(); x++)
13696  {
13697  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
13698  {
13699  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
13700  // OK if a bridge & routes on different tracks
13701  {
13702  for(int x = 0; x < VectorCount; x++)
13703  SearchVector.erase(SearchVector.end() - 1);
13704  Utilities->CallLogPop(238);
13705  return false;
13706  }
13707  }
13708  }
13709 
13710 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
13711  TAllRoutes::TRouteElementPair SecondPair;
13713  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
13714  if(RoutePair.first > -1)
13715  {
13716  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
13717  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
13718  RoutePair.second).ELinkPos)))
13719  {
13720  // still OK if start of an expected route
13721  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
13722  {
13723  for(int x = 0; x < VectorCount; x++)
13724  SearchVector.erase(SearchVector.end() - 1);
13725  Utilities->CallLogPop(239);
13726  return false; // only allow for start of an expected route
13727  }
13728  }
13729  }
13730  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
13731  {
13732  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
13733  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
13734  SecondPair.second).ELinkPos)))
13735  {
13736  // still OK if start of an expected route
13737  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
13738  {
13739  for(int x = 0; x < VectorCount; x++)
13740  SearchVector.erase(SearchVector.end() - 1);
13741  Utilities->CallLogPop(240);
13742  return false; // only allow for start of an expected route
13743  }
13744  }
13745  }
13746 
13747 // check if a train on element, unless a bridge & train on different track
13748 // OK of same train as start element - no drop this
13749 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
13750  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
13751  {
13752  for(int x = 0; x < VectorCount; x++)
13753  SearchVector.erase(SearchVector.end() - 1);
13754  Utilities->CallLogPop(241);
13755  return false;
13756  }
13757  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
13758  {
13759  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
13760  {
13761  for(int x = 0; x < VectorCount; x++)
13762  SearchVector.erase(SearchVector.end() - 1);
13763  Utilities->CallLogPop(242);
13764  return false;
13765  }
13766  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
13767  {
13768  for(int x = 0; x < VectorCount; x++)
13769  SearchVector.erase(SearchVector.end() - 1);
13770  Utilities->CallLogPop(243);
13771  return false;
13772  }
13773  }
13774 
13775 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
13776  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
13777  {
13778  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
13779  {
13780  for(int x = 0; x < VectorCount; x++)
13781  SearchVector.erase(SearchVector.end() - 1);
13782  Utilities->CallLogPop(244);
13783  return false;
13784  }
13785  }
13786 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
13787 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
13788  bool InPrefDirFlag = false;
13789  PrefDirElement1 = BlankElement;
13790  PrefDirElement2 = BlankElement;
13791 
13792  bool FoundFlag;
13793  int PrefDirPos0 = -1;
13794  int PrefDirPos1 = -1;
13795  int PrefDirPos2 = -1;
13796  int PrefDirPos3 = -1;
13798  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13799  int PrefDirVecPos[4] =
13800  {PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3};
13801  for(int x = 0; x < 4; x++)
13802  {
13803  int b = PrefDirVecPos[x];
13804  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
13805  {
13806  InPrefDirFlag = true;
13807  if(PrefDirElement1.TrackVectorPosition == -1)
13808  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
13809  else
13810  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
13811  }
13812  }
13813  if(!InPrefDirFlag)
13814  {
13815  for(int x = 0; x < VectorCount; x++)
13816  SearchVector.erase(SearchVector.end() - 1);
13817  Utilities->CallLogPop(245);
13818  return false;
13819  }
13820 
13821 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
13822 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
13823 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
13825  {
13826  for(int x = 0; x < VectorCount; x++)
13827  SearchVector.erase(SearchVector.end() - 1);
13828  Utilities->CallLogPop(1690);
13829  return false;
13830  }
13831 
13832 // check if found it
13833  if(SearchElement.TrackVectorPosition == RequiredPosition)
13834  {
13835 // need to ensure a signal/buffer/continuation
13836  if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End) &&
13837  (SearchElement.Config[SearchElement.XLinkPos] != Continuation))
13838  {
13839  TrainController->StopTTClockMessage(94, "Must select a valid signal, buffers or continuation"); //added at v2.7.0
13841  for(int x = 0; x < VectorCount; x++)
13842  SearchVector.erase(SearchVector.end() - 1);
13843  Utilities->CallLogPop(246);
13844  return false;
13845  } // if((SearchElement.Config[SearchElement.XLinkPos] != Signal).......
13846  if(AutoSigsFlag)
13847  {
13848  PrefDirElement1.AutoSignals = true;
13849  }
13850  PrefDirElement1.PrefDirRoute = true;
13852  {
13854  {
13855  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
13857  }
13858  for(int x = 0; x < VectorCount; x++)
13859  SearchVector.erase(SearchVector.end() - 1);
13860  Utilities->CallLogPop(1928);
13861  return false;
13862  }
13863  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
13864  VectorCount++; // not really needed but include for tidyness
13865  TotalSearchCount++;
13866  Utilities->CallLogPop(247);
13867  return true;
13868  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
13869 // check if a buffer or continuation (end of search on this leg if not found by now)
13870  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
13871  {
13872  for(int x = 0; x < VectorCount; x++)
13873  SearchVector.erase(SearchVector.end() - 1);
13874  Utilities->CallLogPop(248);
13875  return false;
13876  }
13877 // check if SearchVector exceeds a size of 150
13878  if(SearchVector.size() > 150)
13879  {
13880  for(int x = 0; x < VectorCount; x++)
13881  SearchVector.erase(SearchVector.end() - 1);
13882  Utilities->CallLogPop(1420);
13883  return false;
13884  }
13885 // check if reached a leading point
13886  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
13887  {
13888 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
13889  int SearchPos1 = SearchElement.Attribute + 1;
13890  int SearchPos2;
13891  if(SearchPos1 == 2)
13892  SearchPos1++;
13893  if(SearchPos1 == 1)
13894  SearchPos2 = 3;
13895  else
13896  SearchPos2 = 1;
13897  SearchElement.XLink = SearchElement.Link[SearchPos1];
13898  SearchElement.XLinkPos = SearchPos1;
13899  InPrefDirFlag = false;
13900  if(SearchElement.XLink == PrefDirElement1.XLink)
13901  {
13902  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
13903  InPrefDirFlag = true;
13904  }
13905  else if(SearchElement.XLink == PrefDirElement2.XLink)
13906  {
13907  SearchElement = PrefDirElement2;
13908  InPrefDirFlag = true;
13909  }
13910 // push element with XLink set to position [SearchPos1] if on a PrefDir
13911  if(InPrefDirFlag)
13912  {
13913 // check for a fouled diagonal for leading point for XLinkPos == 1)
13914  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
13915  {
13916  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
13917  {
13918  for(int x = 0; x < VectorCount; x++)
13919  SearchVector.erase(SearchVector.end() - 1);
13920  Utilities->CallLogPop(249);
13921  return false;
13922  }
13923  }
13924  if(AutoSigsFlag)
13925  {
13926  SearchElement.AutoSignals = true;
13927  }
13928  SearchElement.PrefDirRoute = true;
13929  SearchVector.push_back(SearchElement);
13930  VectorCount++;
13931  TotalSearchCount++;
13932 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
13933  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
13934  AutoSigsFlag))
13935  {
13937  {
13939  {
13940  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
13942  }
13943  for(int x = 0; x < VectorCount; x++)
13944  SearchVector.erase(SearchVector.end() - 1);
13945  Utilities->CallLogPop(1929);
13946  return false;
13947  }
13948  Utilities->CallLogPop(250);
13949  return true;
13950  }
13951  else
13952  {
13953 // remove leading point with XLinkPos [1]
13954  SearchVector.erase(SearchVector.end() - 1);
13955  VectorCount--;
13956  }
13957  }
13958 // XLink set to position [SearchPos2]
13959  SearchElement.XLink = SearchElement.Link[SearchPos2];
13960  SearchElement.XLinkPos = SearchPos2;
13961  if(SearchElement.XLink == PrefDirElement1.XLink)
13962  {
13963  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
13964  }
13965  else if(SearchElement.XLink == PrefDirElement2.XLink)
13966  {
13967  SearchElement = PrefDirElement2;
13968  }
13969  else // failed to find a valid exit from the point
13970  {
13971  for(int x = 0; x < VectorCount; x++)
13972  SearchVector.erase(SearchVector.end() - 1);
13973  Utilities->CallLogPop(251);
13974  return false;
13975  }
13976 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
13977  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
13978  {
13979  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
13980  {
13981  for(int x = 0; x < VectorCount; x++)
13982  SearchVector.erase(SearchVector.end() - 1);
13983  Utilities->CallLogPop(252);
13984  return false;
13985  }
13986  }
13987 // push element with XLink set to position [SearchPos2]
13988  if(AutoSigsFlag)
13989  {
13990  SearchElement.AutoSignals = true;
13991  }
13992  SearchElement.PrefDirRoute = true;
13993  SearchVector.push_back(SearchElement);
13994  VectorCount++;
13995  TotalSearchCount++;
13996 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
13997  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
13998  AutoSigsFlag))
13999  {
14001  {
14003  {
14004  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
14006  }
14007  for(int x = 0; x < VectorCount; x++)
14008  SearchVector.erase(SearchVector.end() - 1);
14009  Utilities->CallLogPop(1930);
14010  return false;
14011  }
14012  Utilities->CallLogPop(1592);
14013  return true;
14014  }
14015  else
14016  {
14017  for(int x = 0; x < VectorCount; x++)
14018  SearchVector.erase(SearchVector.end() - 1);
14019  Utilities->CallLogPop(253);
14020  return false;
14021  }
14022  } // if leading point
14023 // here if ordinary element, push it, inc vector & update PrefDirElement ready for next element on PrefDir
14024  SearchElement = PrefDirElement1;
14025  if(AutoSigsFlag)
14026  {
14027  SearchElement.AutoSignals = true;
14028  }
14029  SearchElement.PrefDirRoute = true;
14030  SearchVector.push_back(SearchElement);
14031  VectorCount++;
14032  TotalSearchCount++;
14033  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
14034  PrefDirElement = SearchElement;
14035  } // while(true)
14036 }
14037 
14038 // ---------------------------------------------------------------------------
14039 
14040 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
14041 {
14042 /*
14043  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
14044  and the new or extended route created from that. Hence action varies depending on whether
14045  it is a completely new route, or an extension of an existing route at the beginning or the end.
14046  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
14047  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
14048 
14049  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
14050  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
14051  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
14052  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
14053  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
14054  is decremented;
14055  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
14056  from the existing route, then enter the new route into the AllRoutesVector;
14057  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
14058  then enter the new route into the AllRoutesVector.
14059 
14060  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
14061  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
14062  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
14063  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
14064  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
14065  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
14066  for the new route and return;
14067  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
14068  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
14069 
14070  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
14071  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
14072  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
14073 
14074 */
14075  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
14076  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
14077  if(SearchVector.size() < 1)
14078  {
14079  Utilities->CallLogPop(254);
14080  return;
14081  }
14083  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
14084  {
14085  Utilities->CallLogPop(255);
14086  return;
14087  }
14088 
14089  TAllRoutes::TLockedRouteClass LockedRouteObject;
14090 
14092  unsigned int TruncatePrefDirPosition = 0;
14093 
14094  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
14095 /* if have ReqPosRouteID:
14096  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
14097  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
14098  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
14099  the existing route, then enter the new route into the AllRoutesVector
14100  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
14101  then enter the new route into the AllRoutesVector
14102 */
14103  {
14106  {
14107  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
14108  x++) // start at 1 as first element already in SearchVector
14109  {
14111  }
14112  // note that route numbers in map adjusted when ReqPos route cleared
14114  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
14115  // set during ClearRouteDuringRouteBuildingAt
14117  {
14120  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
14121  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
14122  }
14123  }
14125  {
14127  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
14128  }
14130  {
14131  SearchVector.pop_back();
14132  }
14133  }
14134 
14135  if(StartSelectionRouteID > -1)
14136 /* if have StartSelectionRouteID:
14137  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
14138  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
14139  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
14140  then add it to the start of the new route, then enter the new route into the AllRoutesVector
14141  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
14142 */
14143  {
14145  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
14146  {
14149  {
14150  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
14151  for(unsigned int x = 0; x < SearchVector.size(); x++)
14152  {
14154  RouteNumber, GetFixedSearchElementAt(3, x));
14155  // find & store locked route truncate position in PrefDirVector for later use
14157  {
14158  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
14159  {
14160  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
14161  }
14162  }
14163  }
14165  {
14166  throw Exception("Error - failed to validate extended route for preferred route");
14167  }
14170  if(!AutoSigsFlag)
14171  {
14172  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
14173  }
14174  // now add the reinstated locked route if required and set signals accordingly
14176  {
14177  LockedRouteObject.RouteNumber = RouteNumber;
14178  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
14179  // now reset the signals for the locked route
14180  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
14181  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
14182  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
14183  // return all signals to red in route section to be truncated
14184  {
14185  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
14186  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
14187  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
14188  {
14189  TrackElement.Attribute = 0;
14190  Track->PlotSignal(10, TrackElement, Display);
14191  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
14192  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
14193  }
14194  }
14195  }
14196  AllRoutes->CheckMapAndRoutes(1); // test
14197  Utilities->CallLogPop(256);
14198  return;
14199  }
14201  {
14204  RouteElement.AutoSignals = true;
14205  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true);
14206  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // as above
14207  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
14208  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
14209  }
14210  }
14211  else
14212  {
14214  }
14215 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
14216 // AllRoutesVector hence nothing to do here
14217  }
14218 
14219  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
14220  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
14221  {
14222  throw Exception("Error - failed to validate single route for preferred route");
14223  }
14224  AllRoutes->StoreOneRoute(1, this);
14225  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
14226  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
14227  if(!AutoSigsFlag)
14228  {
14229  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
14230  }
14231  AllRoutes->CheckMapAndRoutes(2); // test
14232  Utilities->CallLogPop(257);
14233 }
14234 
14235 // ---------------------------------------------------------------------------
14236 
14237 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon) // Return true if OK.
14238 {
14239 /*
14240  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
14241  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
14242  & ensure signal/buffers/continuation.
14243  Note that can't select ConsecSignalsRoute for non-preferred routes.
14244  Check if train on element & disallow.
14245  Set default values for retained parameters:-
14246  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
14247  StartSelectionRouteID = route that selection starts in if there is one;
14248 
14249  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
14250  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
14251  validity. This is just for safety reasons, the PrefDir values aren't used.
14252  StartElement1 & 2 are set to these PrefDirelements.
14253 
14254  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
14255 
14256  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
14257  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
14258  blank StartElement2 (only want to use the route element), then return true.
14259  Check if adjacent to start or end of an existing route & disallow if so.
14260  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
14261  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
14262  SetRemainingSearchVectorValues().
14263  Finally add the required element to the SearchVector & return true.
14264 
14265 */
14266  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
14267  AnsiString(VLoc) + "," + AnsiString((short)Callon));
14268  ClearRoute();
14269  int TrackVectorPosition;
14270  TTrackElement TrackElement;
14271  TPrefDirElement FirstElement, LastElement;
14272 
14273  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
14274  {
14275  Utilities->CallLogPop(258);
14276  return false;
14277  }
14278  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
14279  {
14280  if(!Callon)
14281  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
14282 // makes later adjacent route checks too complicated
14283  Utilities->CallLogPop(259);
14284  return false;
14285  }
14286 
14287  if(Track->IsLCAtHV(21, HLoc, VLoc))
14288  {
14289  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
14290  Utilities->CallLogPop(1910);
14291  return false;
14292  }
14293 
14294 // check if selected a train & disallow if so
14295  if(TrackElement.TrainIDOnElement > -1)
14296  {
14297  if(!Callon)
14298  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
14299  Utilities->CallLogPop(260);
14300  return false;
14301  }
14302 
14303 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
14304  TPrefDirElement PrefDirElement;
14305  int LockedVectorNumber;
14306 
14307  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
14308  {
14309  if(!Callon)
14310  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
14311  Utilities->CallLogPop(261);
14312  return false;
14313  }
14314  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
14315  {
14316  if(!Callon)
14317  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
14318  Utilities->CallLogPop(262);
14319  return false;
14320  }
14321 
14323 // AdjacentStartRouteNumber = -1;
14324  StartRoutePosition = TrackVectorPosition;
14325 // StartRouteSelectPosition = TrackVectorPosition;
14326 
14327  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
14328  TPrefDirElement PrefDirElement2(TrackElement);
14329 
14330  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
14331  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
14332  TPrefDirElement BlankElement;
14333 
14334  PrefDirElement1.ELinkPos = 0;
14335  PrefDirElement1.XLinkPos = 1;
14336  PrefDirElement1.ELink = PrefDirElement1.Link[0];
14337  PrefDirElement1.XLink = PrefDirElement1.Link[1];
14338  if(!(PrefDirElement1.EntryExitNumber()))
14339  {
14340  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
14341  // no need for bridge check as bridge selections not allowed
14342  }
14343  PrefDirElement1.CheckCount = 9;
14344  PrefDirElement2.ELinkPos = 1;
14345  PrefDirElement2.XLinkPos = 0;
14346  PrefDirElement2.ELink = PrefDirElement2.Link[1];
14347  PrefDirElement2.XLink = PrefDirElement2.Link[0];
14348  if(!(PrefDirElement2.EntryExitNumber()))
14349  {
14350  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
14351  }
14352  PrefDirElement2.CheckCount = 9; // both now set
14353 
14354 // set StartElements to the above PrefDirElements
14355  StartElement1 = PrefDirElement1;
14356  StartElement2 = PrefDirElement2;
14357 
14358 // no PrefDir check needed as doesn't need to be in a PrefDir
14359 
14360 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
14362  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14363 
14364  if(RoutePair.first > -1)
14365  {
14366  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
14367  {
14368  if(!Callon)
14369  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
14370  Utilities->CallLogPop(263);
14371  return false;
14372  }
14373  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
14374  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
14375  {
14376  if(!Callon)
14377  TrainController->StopTTClockMessage(39, "No forward connection from this position");
14378  Utilities->CallLogPop(264);
14379  return false;
14380  }
14381  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
14382  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
14383  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14384  {
14385  if(!Callon)
14386  TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
14387  Utilities->CallLogPop(265);
14388  return false;
14389  }
14390  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
14392  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
14393  StartElement2 = BlankElement; // only use the route element
14395  Utilities->CallLogPop(266);
14396  return true; // all retained values set
14397  }
14398 
14399  else // selection not in an existing route
14400  {
14401 // check if it's adjacent to start of an an existing route,
14402  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14403  {
14404  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
14405  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
14406  {
14407  if(!Callon)
14408  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
14409  Utilities->CallLogPop(267);
14410  return false;
14411  }
14412  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
14413  {
14414  if(!Callon)
14415  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
14416  Utilities->CallLogPop(268);
14417  return false;
14418  }
14419  }
14420 // check if it's adjacent to end of an an existing route,
14421  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14422  {
14424  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
14425  {
14426  if(!Callon)
14427  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
14428  Utilities->CallLogPop(269);
14429  return false;
14430  }
14431  }
14432  // not in a route or adjacent to start or end of a route
14433  // in this case reset all variable values to -1 & CheckCount to 4
14434  StartElement1.ELink = -1;
14435  StartElement1.ELinkPos = -1;
14436  StartElement1.XLink = -1;
14437  StartElement1.XLinkPos = -1;
14438  StartElement1.EXNumber = -1;
14440  StartElement2 = BlankElement;
14441  SearchVector.push_back(StartElement1);
14442  Utilities->CallLogPop(270);
14443  return true;
14444  }
14445 }
14446 
14447 // ---------------------------------------------------------------------------
14448 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
14449 
14450 /*
14451  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
14452 
14453  Declare the following integers:-
14454  EndPosition - TrackVectorPosition for the selection;
14455  ReqPosRouteID - for the existing route selected if there is one, set to -1 if not;
14456  Check if selection is a valid track element and set EndPosition.
14457  Cancel if select original start element, then check that not points, bridge or crossover.
14458  Check & fail if a train is present at the selection.
14459  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
14460  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
14461  No check needed for selection in EveryPrefDir.
14462  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
14463  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
14464  as don't need it if in a route.
14465  Check if selection adj to start or end of a route and disallow.
14466  Fail if select same route as starting route, though should already have failed earlier if this is so.
14467 
14468  If there's a StartSelectionRouteID then StartElement1 will be set to
14469  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
14470  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
14471  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
14472  to add the new route to the AllRoutesVectorPtr.
14473  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
14474  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
14475  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
14476  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
14477  the search vector values and return.
14478  If not returned yet then have failed to find the required element so return false with no message.
14479 
14480 */
14481 
14482 {
14483 // get EndPosition
14484  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
14485  AnsiString(VLoc));
14486  int EndPosition;
14487 
14488  TotalSearchCount = 0;
14489  ReqPosRouteID = IDInt(-1); // for not used
14490  TTrackElement TrackElement;
14491  TPrefDirElement BlankElement;
14492 
14493  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
14494  {
14495  Utilities->CallLogPop(271);
14496  return false;
14497  }
14498 // EndPosition = EndSelectPosition;
14499 // cancel selection if on original start element
14500  if(EndPosition == StartRoutePosition)
14501  {
14502  Utilities->CallLogPop(272);
14503  return false;
14504  }
14505 
14506  if(Track->IsLCAtHV(22, HLoc, VLoc))
14507  {
14508  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
14509  Utilities->CallLogPop(1911);
14510  return false;
14511  }
14512 
14513  if((TrackElement.TrackType == Points) && !Callon)
14514  {
14515  if(!Callon)
14516  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
14517 // makes later adjacent route checks too complicated
14518  Utilities->CallLogPop(273);
14519  return false;
14520  }
14521 
14522  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
14523  {
14524  if(!Callon)
14525  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
14526 // makes later adjacent route checks too complicated
14527  Utilities->CallLogPop(1861);
14528  return false;
14529  }
14530 
14531 // check if train on element
14532  if(TrackElement.TrainIDOnElement > -1)
14533  {
14534  if(!Callon)
14535  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
14536  Utilities->CallLogPop(274);
14537  return false;
14538  }
14539 
14540 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
14541 // check passed)
14542  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
14543  TPrefDirElement EndElement2(TrackElement);
14544 
14545  EndElement1.TrackVectorPosition = EndPosition;
14546  EndElement2.TrackVectorPosition = EndPosition;
14547  EndElement1.ELinkPos = 0;
14548  EndElement1.XLinkPos = 1;
14549  EndElement1.ELink = EndElement1.Link[0];
14550  EndElement1.XLink = EndElement1.Link[1];
14551  if(!(EndElement1.EntryExitNumber()))
14552  {
14553  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
14554  }
14555  EndElement1.CheckCount = 9;
14556  EndElement2.ELinkPos = 1;
14557  EndElement2.XLinkPos = 0;
14558  EndElement2.ELink = EndElement2.Link[1];
14559  EndElement2.XLink = EndElement2.Link[0];
14560  if(!(EndElement2.EntryExitNumber()))
14561  {
14562  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
14563  }
14564  EndElement2.CheckCount = 9; // both now set
14565 
14566 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
14567 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
14568 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
14569 
14570  if(EndElement1.HLoc >= StartElement1.HLoc)
14571  {
14573  SearchLimitHighH = EndElement1.HLoc + 15;
14574  }
14575  else
14576  {
14577  SearchLimitLowH = EndElement1.HLoc - 15;
14579  }
14580 
14581  if(EndElement1.VLoc >= StartElement1.VLoc)
14582  {
14584  SearchLimitHighV = EndElement1.VLoc + 15;
14585  }
14586  else
14587  {
14588  SearchLimitLowV = EndElement1.VLoc - 15;
14590  }
14591 
14592 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
14593  check & TotalSearchCounts check
14594  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
14595  {
14596  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
14597  Utilities->CallLogPop(1694);
14598  return false;
14599  }
14600 */
14601 // don't need EveryPrefDir check for NonPreferredRoute
14602 
14603 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
14604 // bool InRoute = false;
14606  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14607 
14608  if(RoutePair.first > -1)
14609  {
14610  if(RoutePair.second != 0) // not first element in existing route so no good
14611  {
14612  if(!Callon)
14613  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
14614  Utilities->CallLogPop(275);
14615  return false;
14616  }
14617  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
14618 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
14619  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
14620  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
14621  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14622  {
14623  if(!Callon)
14624  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
14625  Utilities->CallLogPop(276);
14626  return false;
14627  }
14628  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
14629  EndElement2 = BlankElement; // only need the route element
14630  EndPosition = EndElement1.TrackVectorPosition;
14631  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
14632  }
14633 
14634 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
14635  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14636  {
14637  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
14638  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
14639 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14640 // && (AdjPosition != StartRoutePosition))
14641  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14642  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14643  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
14644  {
14645  if(!Callon)
14646  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
14647  Utilities->CallLogPop(277);
14648  return false;
14649  }
14650 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
14651 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
14652  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
14653  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14654  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
14655  (AdjPosition != StartRoutePosition))
14656  {
14657  if(!Callon)
14658  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
14659  Utilities->CallLogPop(278);
14660  return false;
14661  }
14662 
14663 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
14665  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
14666  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
14667  {
14668  if(!Callon)
14669  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
14670  Utilities->CallLogPop(279);
14671  return false;
14672  }
14673  }
14674 
14675 // check for same route as start element
14677  {
14678  if(!Callon)
14679  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
14680  Utilities->CallLogPop(280);
14681  return false;
14682  }
14683 
14684 // check for a looping route
14685  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
14686  {
14688  {
14689  if(!Callon)
14690  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
14691  Utilities->CallLogPop(1845);
14692  return false;
14693  }
14694  }
14695 
14696 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
14697 // so search from this element.
14698 
14699  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
14700 
14701  if(StartSelectionRouteID > -1)
14702  {
14703  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID))
14704  {
14706  if(PointsToBeChanged(0))
14707  {
14708  PointsChanged = true;
14709  }
14710  Utilities->CallLogPop(281);
14711  return true;
14712  }
14713  else
14714  {
14715  if(!Callon)
14717  Utilities->CallLogPop(282);
14718  return false;
14719  }
14720  }
14721  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
14722  // search on the 2 ways out of the element, which has to be a 2-ended element
14723  {
14724 // check if selection adjacent to start element and if so use that
14725  if(SearchVector.at(0).Conn[0] == EndPosition)
14726  {
14727  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID))
14728  {
14730  if(PointsToBeChanged(1))
14731  {
14732  PointsChanged = true;
14733  }
14734  Utilities->CallLogPop(283);
14735  return true;
14736  }
14737  else
14738  {
14739  if(!Callon)
14741  Utilities->CallLogPop(284);
14742  return false;
14743  }
14744  }
14745  else if(SearchVector.at(0).Conn[1] == EndPosition)
14746  {
14747  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID))
14748  {
14750  if(PointsToBeChanged(2))
14751  {
14752  PointsChanged = true;
14753  }
14754  Utilities->CallLogPop(285);
14755  return true;
14756  }
14757  else
14758  {
14759  if(!Callon)
14761  Utilities->CallLogPop(286);
14762  return false;
14763  }
14764  }
14765  // now start off in the best direction
14766  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
14767 
14768  if(SearchVector.at(0).Config[BestPos] != End)
14769  {
14770  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14771  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID))
14772  {
14774  if(PointsToBeChanged(3))
14775  {
14776  PointsChanged = true;
14777  }
14778  Utilities->CallLogPop(287);
14779  return true;
14780  }
14781  }
14782  if(SearchVector.at(0).Config[1 - BestPos] != End)
14783  {
14784  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14785  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID))
14786  {
14788  if(PointsToBeChanged(4))
14789  {
14790  PointsChanged = true;
14791  }
14792  Utilities->CallLogPop(288);
14793  return true;
14794  }
14795  }
14796  }
14797  if(!Callon)
14799  Utilities->CallLogPop(289);
14800  return false;
14801 }
14802 
14803 // ---------------------------------------------------------------------------
14804 
14805 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
14806 /*
14807  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
14808  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
14809  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
14810  Keep a count of entries in SearchVector during the current function call, so that this number can be
14811  erased for an unproductive branch search.
14812  First check (within the loop) whether XLink leads to an End & return false if so.
14813  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
14814  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
14815  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
14816  train on element (unless a bridge & train on different track), or if element
14817  fouls an existing diagonal route (except if element is a leading point - these checked later).
14818  Then check if found required element. If so save it & return true.
14819  If not the required element check if buffer or continuation, & if so erase all searchvector
14820  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
14821  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
14822  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
14823  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
14824  When return true have 8 items from CheckCount established, only waiting for EXNumber
14825 */
14826 {
14827  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
14828  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
14829  int VectorCount = 0;
14830 
14831 // check for a fouled diagonal for first element. Added for v1.3.2
14832  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
14833  (CurrentTrackElement.Link[XLinkPos] == 9))
14834  {
14835  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
14836  {
14837  for(int x = 0; x < VectorCount; x++)
14838  SearchVector.erase(SearchVector.end() - 1);
14839  Utilities->CallLogPop(2044);
14840  return false;
14841  }
14842  }
14843 
14844  while(true)
14845  {
14846  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
14847  {
14848  for(int x = 0; x < VectorCount; x++)
14849  SearchVector.erase(SearchVector.end() - 1);
14850  Utilities->CallLogPop(1927);
14851  return false;
14852  }
14853  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
14854  {
14855  for(int x = 0; x < VectorCount; x++)
14856  SearchVector.erase(SearchVector.end() - 1);
14857  Utilities->CallLogPop(290);
14858  return false;
14859  }
14860  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
14861  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
14862  TPrefDirElement SearchElement(NextTrackElement);
14863  SearchElement.TrackVectorPosition = NextPosition;
14864  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
14865  SearchElement.ELinkPos = NextELinkPos;
14866  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
14867  int NextXLinkPos;
14868  if(SearchElement.ELinkPos == 0)
14869  NextXLinkPos = 1;
14870  if(SearchElement.ELinkPos == 1)
14871  NextXLinkPos = 0;
14872  if(SearchElement.ELinkPos == 2)
14873  NextXLinkPos = 3;
14874  if(SearchElement.ELinkPos == 3)
14875  NextXLinkPos = 2;
14876  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
14877  {
14878  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
14879  // but may be buffers, continuation or gap
14880  SearchElement.XLinkPos = NextXLinkPos;
14881  }
14882 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
14883 // can't set XLink or XLinkPos yet if the element is a leading point.
14884 
14885 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
14886  for(unsigned int x = 0; x < SearchVector.size(); x++)
14887  {
14888  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
14889  {
14890  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
14891  // OK if it's a bridge & routes on different tracks
14892  {
14893  for(int x = 0; x < VectorCount; x++)
14894  SearchVector.erase(SearchVector.end() - 1);
14895  Utilities->CallLogPop(291);
14896  return false;
14897  }
14898  }
14899  }
14900 
14901 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
14902  TAllRoutes::TRouteElementPair SecondPair;
14904  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
14905  if(RoutePair.first > -1)
14906  {
14907  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
14908  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
14909  RoutePair.second).ELinkPos)))
14910  {
14911  // still OK if start of an expected route
14912  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
14913  {
14914  for(int x = 0; x < VectorCount; x++)
14915  SearchVector.erase(SearchVector.end() - 1);
14916  Utilities->CallLogPop(292);
14917  return false; // only allow for start of an expected route
14918  }
14919  }
14920  }
14921  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
14922  {
14923  // OK if it's a bridge & routes on different tracks
14924  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
14925  SecondPair.second).ELinkPos)))
14926  {
14927  // still OK if start of an expected route
14928  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
14929  {
14930  for(int x = 0; x < VectorCount; x++)
14931  SearchVector.erase(SearchVector.end() - 1);
14932  Utilities->CallLogPop(293);
14933  return false; // only allow for start of an expected route
14934  }
14935  }
14936  }
14937 
14938 // check if a train on element, unless a bridge & train on different track
14939 // OK of same train as start element - no, drop this
14940 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
14941  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
14942  {
14943  for(int x = 0; x < VectorCount; x++)
14944  SearchVector.erase(SearchVector.end() - 1);
14945  Utilities->CallLogPop(294);
14946  return false;
14947  }
14948  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
14949  {
14950  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
14951  {
14952  for(int x = 0; x < VectorCount; x++)
14953  SearchVector.erase(SearchVector.end() - 1);
14954  Utilities->CallLogPop(295);
14955  return false;
14956  }
14957  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
14958  {
14959  for(int x = 0; x < VectorCount; x++)
14960  SearchVector.erase(SearchVector.end() - 1);
14961  Utilities->CallLogPop(296);
14962  return false;
14963  }
14964  }
14965 
14966 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
14967  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
14968  {
14969  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
14970  {
14971  for(int x = 0; x < VectorCount; x++)
14972  SearchVector.erase(SearchVector.end() - 1);
14973  Utilities->CallLogPop(297);
14974  return false;
14975  }
14976  }
14977 
14978 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
14979 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
14980 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
14982  {
14983  for(int x = 0; x < VectorCount; x++)
14984  SearchVector.erase(SearchVector.end() - 1);
14985  Utilities->CallLogPop(1689);
14986  return false;
14987  }
14988 
14989 // check if found it
14990  if(SearchElement.TrackVectorPosition == RequiredPosition)
14991  {
14992  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
14993  {
14994  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
14995  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
14996  else
14997  SearchElement.XLinkPos = 1;
14998 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
14999  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
15000  }
15001  SearchVector.push_back(SearchElement);
15002  VectorCount++; // not really needed but include for tidyness
15003  TotalSearchCount++;
15004  Utilities->CallLogPop(298);
15005  return true;
15006  }
15007 // Not the required element - check if a buffer or continuation
15008  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
15009  {
15010  for(int x = 0; x < VectorCount; x++)
15011  SearchVector.erase(SearchVector.end() - 1);
15012  Utilities->CallLogPop(299);
15013  return false;
15014  }
15015 
15016 // check if SearchVector exceeds a size of 150
15017  if(SearchVector.size() > 150)
15018  {
15019  for(int x = 0; x < VectorCount; x++)
15020  SearchVector.erase(SearchVector.end() - 1);
15021  Utilities->CallLogPop(1421);
15022  return false;
15023  }
15024 
15025 // check if reached a leading point
15026  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
15027  {
15028 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
15029  int SearchPos1 = SearchElement.Attribute + 1;
15030  int SearchPos2;
15031  if(SearchPos1 == 2)
15032  SearchPos1++;
15033  if(SearchPos1 == 1)
15034  SearchPos2 = 3;
15035  else
15036  SearchPos2 = 1;
15037 // push element with XLink set to position [SearchPos1]
15038  SearchElement.XLink = SearchElement.Link[SearchPos1];
15039  SearchElement.XLinkPos = SearchPos1;
15040 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
15041  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15042  {
15043  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15044  {
15045  for(int x = 0; x < VectorCount; x++)
15046  SearchVector.erase(SearchVector.end() - 1);
15047  Utilities->CallLogPop(300);
15048  return false;
15049  }
15050  }
15051  SearchVector.push_back(SearchElement);
15052  VectorCount++;
15053  TotalSearchCount++;
15054 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
15055 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
15056 // recursive search as has to be a TTrackElement for non-preferred route searches
15057  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID))
15058  {
15059  Utilities->CallLogPop(301);
15060  return true;
15061  }
15062  else
15063  {
15064 // remove leading point with XLinkPos [SearchPos1]
15065  SearchVector.erase(SearchVector.end() - 1);
15066  VectorCount--;
15067 // push element with XLink set to position [SearchPos2]
15068  SearchElement.XLink = SearchElement.Link[SearchPos2];
15069  SearchElement.XLinkPos = SearchPos2;
15070 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
15071  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15072  {
15073  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15074  {
15075  for(int x = 0; x < VectorCount; x++)
15076  SearchVector.erase(SearchVector.end() - 1);
15077  Utilities->CallLogPop(302);
15078  return false;
15079  }
15080  }
15081  SearchVector.push_back(SearchElement);
15082  VectorCount++;
15083  TotalSearchCount++;
15084 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
15085  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID))
15086  {
15087  Utilities->CallLogPop(303);
15088  return true;
15089  }
15090  else
15091  {
15092  for(int x = 0; x < VectorCount; x++)
15093  SearchVector.erase(SearchVector.end() - 1);
15094  Utilities->CallLogPop(304);
15095  return false;
15096  }
15097  }
15098  } // if leading point
15099 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
15100 // ready for next element on route
15101  SearchVector.push_back(SearchElement);
15102  VectorCount++;
15103  TotalSearchCount++;
15104  CurrentTrackElement = SearchElement;
15105  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
15106  } // while(true)
15107 }
15108 
15109 // ---------------------------------------------------------------------------
15110 
15112 
15113 /*
15114  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
15115  having all values set (since not necessarily on PrefDirs).
15116  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
15117  (if it was the start), so these are checked first and set if necessary. All elements now have
15118  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
15119  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
15120  to set the route colour and direction graphics.
15121 */
15122 
15123 {
15124  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
15125  if(SearchVector.size() == 0)
15126  {
15127  throw Exception("Error, SearchVector empty");
15128  }
15129 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
15130 // hence need to examine and update it if necessary
15131  TPrefDirElement SecondElement;
15132 
15133  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
15134  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
15135  // need above check or SecondElement will fail
15136  {
15137  SecondElement = SearchVector.at(1);
15138  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
15139  for(int x = 0; x < 4; x++)
15140  {
15141  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
15142  {
15143  if(SearchVector.at(0).XLink == -1) // i.e. not set
15144  {
15145  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
15146  SearchVector.at(0).XLinkPos = x;
15147  }
15148  int ELinkPos;
15149  if(SearchVector.at(0).XLinkPos == 0)
15150  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
15151  // linked to 1st searchvector element, & if XLink was set then x may not correspond
15152  if(SearchVector.at(0).XLinkPos == 1)
15153  ELinkPos = 0;
15154  if(SearchVector.at(0).XLinkPos == 2)
15155  ELinkPos = 3;
15156  if(SearchVector.at(0).XLinkPos == 3)
15157  ELinkPos = 2;
15158  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
15159  {
15160  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
15161  SearchVector.at(0).ELinkPos = ELinkPos;
15162  }
15163  break; // no point going any further
15164  }
15165  }
15166  }
15167  for(unsigned int x = 0; x < SearchVector.size(); x++)
15168  {
15169  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
15170 // set EXNumber
15171  if(!(SearchVector.at(x).EntryExitNumber()))
15172  {
15173  throw Exception("Error in EntryExitNumber 3");
15174  }
15175  SearchVector.at(x).CheckCount++;
15176 // all values now incorporated
15177  }
15178 
15179  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
15180 // This function is only called here for nonsignals routes, so AutoSigsFlag & PrefDirRoute both false
15181 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
15182  Utilities->CallLogPop(305);
15183 }
15184 
15185 // ---------------------------------------------------------------------------
15186 
15188 
15189 /*
15190  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
15191  AutoSigsRoute.
15192  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
15193  beginning or the end.
15194  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
15195  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
15196  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
15197  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
15198  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
15199  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
15200  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
15201 
15202  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
15203  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
15204  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
15205  route at the start.
15206 
15207  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
15208  for the new route and return.
15209 */
15210 
15211 {
15212  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
15213  AnsiString(ReqPosRouteID.GetInt()));
15214  if(SearchVector.size() < 1)
15215  {
15216  Utilities->CallLogPop(306);
15217  return;
15218  }
15219  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
15220  if(!ValidatePrefDir(6))
15221  {
15222  Utilities->CallLogPop(307);
15223  return;
15224  }
15225 
15226  TAllRoutes::TLockedRouteClass LockedRouteObject;
15227 
15229  unsigned int TruncatePrefDirPosition = 0;
15230 
15231  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
15232 /* if have ReqPosRouteID:
15233  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
15234  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15235  then enter the new route into the AllRoutesVector
15236 */
15237  {
15239  {
15240  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
15241  x++) // start at 1 as first element already in SearchVector
15242  {
15244  }
15245  // note that route numbers in map adjusted when ReqPos route cleared
15247  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
15248  // set during ClearRouteDuringRouteBuildingAt)
15250  {
15253  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
15254  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
15255  }
15256  }
15258  {
15259  SearchVector.pop_back();
15260  }
15261  }
15262 
15263  if(StartSelectionRouteID > -1)
15264 /* if have StartSelectionRouteID:
15265  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
15266  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
15267 */
15268  {
15270  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
15271  {
15273  {
15274  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
15275  for(unsigned int x = 0; x < SearchVector.size(); x++)
15276  {
15278  RouteNumber, GetFixedSearchElementAt(7, x));
15279  // find & store locked route truncate position in PrefDirVector for later use
15281  {
15282  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
15283  {
15284  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
15285  }
15286  }
15287  }
15289  {
15290  throw Exception("Failed to validate extended route for nonpreferred route");
15291  }
15294  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // PrefDirRoute is false
15295  // now add the reinstated locked route if required and set signals accordingly
15296  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
15297  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
15298  // that I haven't thought of
15300  {
15301  LockedRouteObject.RouteNumber = RouteNumber;
15302  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
15303  // now reset the signals for the locked route
15304  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
15305  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
15306  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
15307  // return all signals to red in route section to be truncated
15308  {
15309  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
15310  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
15311  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
15312  {
15313  TrackElement.Attribute = 0;
15314  Track->PlotSignal(11, TrackElement, Display);
15315  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
15316  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
15317  }
15318  }
15319  }
15320  AllRoutes->CheckMapAndRoutes(3); // test
15321  Utilities->CallLogPop(308);
15322  return;
15323  }
15324  }
15325  else
15326  {
15328  }
15329 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
15330 // hence nothing to do here
15331  }
15332 
15333  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
15334  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
15335  {
15336  throw Exception("Failed to validate single route for nonpreferred route");
15337  }
15338  AllRoutes->StoreOneRoute(2, this);
15339  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
15340  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
15341  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
15342  AllRoutes->CheckMapAndRoutes(4); // test
15343  Utilities->CallLogPop(309);
15344 }
15345 
15346 // ---------------------------------------------------------------------------
15347 
15348 void TOneRoute::SetRoutePoints(int Caller) const
15349 /*
15350  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
15351  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
15352  when they were created.
15353 */
15354 {
15355  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
15356  if(!PrefDirVector.empty())
15357  {
15358  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
15359  {
15360  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) // 1=straight trailing
15361  {
15362  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
15363  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
15364  }
15365  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) // 3=diverging trailing
15366  {
15367  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
15368  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
15369  }
15370  }
15371  }
15372  Utilities->CallLogPop(327);
15373 }
15374 
15375 // ---------------------------------------------------------------------------
15376 
15377 void TOneRoute::SetRouteSignals(int Caller) const
15378 /* Used for new train additions in AddTrain and in route setting
15379  Set the signals as follows:-
15380  First check whether there is a linked forward route, and if so use FindForwardTargetSignalAttribute to work along it from the start
15381  until find a train (return Attribute = 0 & NextForwardLinkedRouteNumber = -1), a buffer (return Attribute = 1 &
15382  NextForwardLinkedRouteNumber = -1), a continuation (return Attribute = 3 & NextForwardLinkedRouteNumber = -1) or a forward-facing
15383  signal. If find a signal its attribute value + 1 up to a maximum value of 3 is returned & NextForwardLinkedRouteNumber = -1.
15384  The above Attribute values represent the 'target' attribute, from which all rearwards signals in turn in the new route are set,
15385  the first using the returned attribute value and subsequent ones incrementing the Attribute up to a maximum of 3. All the foregoing
15386  return true, as does finding none of the above and no onward linked forward route (NextForwardLinkedRouteNumber = -1). If none
15387  of the foregoing are found but there is a further forward linked forward route then the function returns false with
15388  NextForwardLinkedRouteNumber = the next forward linked route number, to allow that to be examined similarly, and Attribute = 0.
15389 
15390  When the target Attribute is found (will be 0 if no forward linked route), then SetAllRearwardsSignals is used to work back from
15391  the end of the route setting each forward-facing signal one step nearer green as described above, until either reach the end of all
15392  linked rearwards routes or find a train. If find a train in the current route then signals behind it (and behind any other trains
15393  in the current route) are set appropriately (including in linked rear routes), but if find a train in a linked rear route then no
15394  further signals are set. If there is no forward linked route and the front end of the current route is a buffer then
15395  SetAllRearwardsSignals (in its call to SetRearwardsSignalsReturnFalseForTrain) treats it as a red signal, and if a continuation,
15396  as a green signal.
15397 */
15398 {
15399  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
15400  if(!PrefDirVector.empty())
15401  {
15402  // get target Attribute value, check first if there is a forward linked route
15403  TPrefDirElement LastElement = GetFixedPrefDirElementAt(185, PrefDirSize() - 1);
15404  TPrefDirElement FirstElement = GetFixedPrefDirElementAt(186, 0);
15405  int ForwardLinkedRouteNumber, Attribute = 0;
15406  if(LastElement.Conn[LastElement.XLinkPos] > -1)
15407  // Note that LastElement can't be points but can be linked to points
15408  {
15409  if(AllRoutes->GetRouteTypeAndNumber(16, LastElement.Conn[LastElement.XLinkPos], LastElement.ConnLinkPos[LastElement.XLinkPos],
15410  ForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
15411  {
15412  if(ForwardLinkedRouteNumber > -1)
15413  {
15414  int NextForwardLinkedRouteNumber = -1;
15415  while(!(AllRoutes->GetFixedRouteAt(171, ForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(1, NextForwardLinkedRouteNumber,
15416  Attribute)))
15417  {
15418  ForwardLinkedRouteNumber = NextForwardLinkedRouteNumber;
15419  }
15420  // if find a train before a signal then Attribute = 0, else if find end of route is a buffer then Attribute = 1, or a continuation then
15421  // Attribute = 3, else if find signal then Attribute = (signal attribute + 1) up to a max value of 3. All these return true, if find a
15422  // forward linked route then the routenumber is set in NextForwardLinkedRouteNumber, Attribute = 0 & returns false.
15423  }
15424  }
15425  }
15426  int RouteNumber;
15427  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
15428  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
15429  if(RouteType != TAllRoutes::NoRoute)
15430  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
15431  {
15432  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
15433  }
15434  }
15435  Utilities->CallLogPop(1720);
15436 }
15437 
15438 // ---------------------------------------------------------------------------
15439 
15440 bool TOneRoute::PointsToBeChanged(int Caller) const
15441 { // true if at any point in SearchVector points have to be changed
15442  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
15443  if(!SearchVector.empty())
15444  {
15445  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
15446  {
15447  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=straight trailing
15448  {
15449  if(Track->TrackElementAt(752, SearchPtr->TrackVectorPosition).Attribute != 0) // 0=straight or LH
15450  {
15451  Utilities->CallLogPop(1717);
15452  return true;
15453  }
15454  }
15455  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=diverging trailing
15456  {
15457  if(Track->TrackElementAt(753, SearchPtr->TrackVectorPosition).Attribute != 1) // 1=diverging or RH
15458  {
15459  Utilities->CallLogPop(1718);
15460  return true;
15461  }
15462  }
15463  }
15464  }
15465  Utilities->CallLogPop(1719);
15466  return false;
15467 }
15468 
15469 // ---------------------------------------------------------------------------
15470 
15471 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
15472 /*
15473  Works forward through the route until finds:-
15474  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
15475  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
15476  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
15477  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
15478  (e) forward-facing signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true;
15479  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 &
15480  returns true;
15481  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
15482 */
15483 {
15484  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
15485  Attribute = 0;
15486  NextForwardLinkedRouteNumber = -1;
15487  for(unsigned int x = 0; x < PrefDirSize(); x++)
15488  {
15489  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
15490  if(PrefDirVector.at(x).TrackType == Bridge)
15491  {
15492  if(PrefDirVector.at(x).XLinkPos < 2)
15493  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
15494  else
15495  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
15496  }
15497  if(TrainID != -1)
15498  {
15499  Utilities->CallLogPop(328);
15500  return true;
15501  }
15502  if(PrefDirVector.at(x).TrackType == Buffers)
15503  {
15504  Attribute = 1;
15505  Utilities->CallLogPop(329);
15506  return true;
15507  }
15508  if(PrefDirVector.at(x).TrackType == Continuation)
15509  {
15510  Attribute = 3;
15511  Utilities->CallLogPop(330);
15512  return true;
15513  }
15514  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
15515  {
15516  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
15517  {
15518  Attribute = 0;
15519  Utilities->CallLogPop(1950);
15520  return true;
15521  }
15522  }
15523  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
15524  {
15525  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute + 1;
15526  if(Attribute > 3)
15527  Attribute = 3;
15528  Utilities->CallLogPop(331);
15529  return true;
15530  }
15531  if(x == PrefDirSize() - 1)
15532  {
15533  TPrefDirElement LastElement = PrefDirVector.at(x);
15534  if(LastElement.Conn[LastElement.XLinkPos] > -1)
15535  {
15536  if(AllRoutes->GetRouteTypeAndNumber(2, LastElement.Conn[LastElement.XLinkPos],
15537  Track->GetNonPointsOppositeLinkPos(LastElement.ConnLinkPos[LastElement.XLinkPos]), NextForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
15538  {
15539  Attribute = 0;
15540  Utilities->CallLogPop(332);
15541  return false;
15542  }
15543  }
15544  }
15545  }
15546  Utilities->CallLogPop(333);
15547  return true;
15548 }
15549 
15550 // ---------------------------------------------------------------------------
15551 
15552 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
15553 /*
15554  This function is only called by TAllRoutes::SetAllRearwardsSignals.
15555 
15556  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
15557  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
15558  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
15559  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
15560  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
15561  a route.
15562 
15563  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
15564  signal. If find a signal (but see note below) set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
15565  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3. On completion Attribute is
15566  passed back from the function as a reference. If no train is found before the beginning of the route is reached the function returns true.
15567 
15568  In setting signals skip the first position if it's a signal and if truncating - otherwise the truncated signal counts as the first red
15569  and the next rearwards signal becomes yellow, although it's the first in the route
15570 */
15571 {
15572  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrain," + AnsiString(Attribute) + "," +
15573  AnsiString(PrefDirVectorStartPosition));
15574  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
15575  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
15576 // if no train between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
15577 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
15578  bool SkipContinuationAndBufferAttributeChange = false;
15579 
15580  if(!PrefDirVector.empty())
15581  {
15582  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
15583  {
15584  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
15585  if(PrefDirPtr->TrackType == Bridge)
15586  {
15587  if(PrefDirPtr->XLinkPos < 2)
15588  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
15589  else
15590  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
15591  }
15592  if(TrainID != -1)
15593  {
15594  SkipContinuationAndBufferAttributeChange = true;
15595  break;
15596  }
15597  }
15598 
15601  {
15602  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
15603  AutoSigVectorIT++)
15604  {
15605  if(!AllRoutes->AllRoutesVector.empty())
15606  {
15607  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
15608  {
15609  SkipContinuationAndBufferAttributeChange = true;
15610  break;
15611  }
15612  }
15613  }
15614  }
15615 
15617  SkipContinuationAndBufferAttributeChange = true;
15618 
15619  if(!SkipContinuationAndBufferAttributeChange)
15620  {
15621  if(PrefDirVector.back().TrackType == Buffers)
15622  Attribute = 1; // treat buffer as red signal
15623  if(PrefDirVector.back().TrackType == Continuation)
15624  Attribute = 3; // treat continuation as a green signal
15625  }
15626 
15627  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
15628  {
15629  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
15630  if(PrefDirPtr->TrackType == Bridge)
15631  {
15632  if(PrefDirPtr->XLinkPos < 2)
15633  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
15634  else
15635  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
15636  }
15637  if(TrainID != -1)
15638  {
15639  Utilities->CallLogPop(334);
15640  return false;
15641  }
15642  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
15643  // the attribute to 0 so first signal behind the LC is red
15644  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
15645  {
15646  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
15647  {
15648  Attribute = 0;
15649  }
15650  }
15651 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
15652 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
15653  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
15654  {
15655  if((!AllRoutes->RouteTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
15656  PrefDirPtr->PrefDirRoute)
15657  {
15658  if(Attribute < 3)
15659  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
15660  else
15661  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
15662  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
15663  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
15664  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
15665  {
15666  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
15667  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
15668  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
15669  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
15670  }
15671  if(Attribute < 3)
15672  Attribute++;
15673  Display->Update(); // update after recent plots
15674  }
15675  }
15676  }
15677  }
15678  Utilities->CallLogPop(335);
15679  return true;
15680 }
15681 
15682 // ---------------------------------------------------------------------------
15683 
15684 void TOneRoute::GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
15685 /*
15686  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
15687  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
15688  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
15689  Selection invalid if select a bridge; trying to leave a single element; last element to be left
15690  not a signal (for PrefDirRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
15691  PrefDirRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
15692  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
15693  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
15694 */
15695 {
15696  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
15697  "," + AnsiString((short)PrefDirRoute));
15698  bool ElementInRoute = false;
15699  bool TrainOccupyingRoute = false;
15700 
15701  for(unsigned int b = 0; b < PrefDirSize(); b++)
15702  {
15703  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
15704  {
15705  ElementInRoute = true;
15706  break;
15707  }
15708  }
15709  if(!ElementInRoute)
15710  {
15711  ReturnFlag = NotInRoute;
15712  Utilities->CallLogPop(336);
15713  return;
15714  }
15715 // it is in the route so continue, first look for a train or a flashing level crossing
15716  for(int b = PrefDirSize() - 1; b >= 0; b--)
15717  {
15718  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
15719  if(PrefDirVector.at(b).TrackType == Bridge)
15720  {
15721  if(PrefDirVector.at(b).XLinkPos < 2)
15722  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
15723  else
15724  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
15725  }
15726  if(TrainID != -1)
15727  {
15728 // TrainController->StopTTClockMessage(56, "Can't truncate a route that is occupied by a train");
15729 // ReturnFlag = InRouteFalse;
15730 // Utilities->CallLogPop(337);
15731 // return;
15732 // above removed at v2.1.0 so that routes can be locked when occupied, below added
15733  TrainOccupyingRoute = true; // train is forward of the truncate point
15734  }
15735  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
15736  {
15737  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
15738  ReturnFlag = InRouteFalse;
15739  Utilities->CallLogPop(1941);
15740  return;
15741  }
15742  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
15743  {
15744  break; // OK found truncate element & no flashing LC in front
15745  }
15746  }
15747 
15748  for(unsigned int b = 0; b < PrefDirSize(); b++)
15749  {
15750  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc)) // b = the truncate point
15751  {
15752  if(PrefDirVector.at(b).TrackType == Bridge)
15753  {
15754  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncate point");
15755  ReturnFlag = InRouteFalse;
15756  Utilities->CallLogPop(338);
15757  return;
15758  }
15759  if(b == 1)
15760  {
15761  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
15762  ReturnFlag = InRouteFalse;
15763  Utilities->CallLogPop(339);
15764  return;
15765  }
15766  if(b > 0)
15767  {
15768  TPrefDirElement TempElement = PrefDirVector.at(b - 1);
15769  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
15770  {
15771  if(TempElement.Config[TempElement.XLinkPos] != Signal)
15772  {
15773  TrainController->StopTTClockMessage(59, "Must truncate to a valid signal - select position after signal");
15774  ReturnFlag = InRouteFalse;
15775  Utilities->CallLogPop(340);
15776  return;
15777  }
15778  }
15779  else
15780  {
15781  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
15782  {
15783  TrainController->StopTTClockMessage(60, "Can't truncate to points, bridge or crossover");
15784  ReturnFlag = InRouteFalse;
15785  Utilities->CallLogPop(341);
15786  return;
15787  }
15788  }
15789  }
15790 
15791  int RouteNumber;
15793 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
15794 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
15795 
15796 // check if part of this route already locked & disallow if so
15797  if(!(AllRoutes->LockedRouteVector.empty()))
15798  {
15800  {
15801  if(LRVIT->RouteNumber == RouteNumber)
15802  {
15803  TrainController->StopTTClockMessage(61, "Can't truncate a route that is already part-locked");
15804  ReturnFlag = InRouteFalse;
15805  Utilities->CallLogPop(749);
15806  return;
15807  }
15808  }
15809  }
15810 
15811  if(AllRoutes->RouteLockingRequired(0, RouteNumber, b) || TrainOccupyingRoute) // added TrainOccupyingRoute at v2.1.0,
15812  // RouteLockingRequired only checks for trains approaching
15813  {
15816  int button = Application->MessageBox(L"Train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
15817  L"Warning!", MB_YESNO | MB_ICONWARNING);
15818  TrainController->BaseTime = TDateTime::CurrentDateTime();
15820  if(button == IDNO)
15821  {
15822  ReturnFlag = InRouteTrue; // still return true even though don't act on it
15823  Utilities->CallLogPop(342);
15824  return;
15825  }
15826  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(b).TrackVectorPosition).ElementID);
15827  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
15828  TAllRoutes::TLockedRouteClass LockedRoute;
15829  bool ExistingLockedRouteModified = false;
15830  LockedRoute.RouteNumber = RouteNumber;
15831  LockedRoute.TruncateTrackVectorPosition = PrefDirVector.at(b).TrackVectorPosition;
15832  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
15833  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
15834  LockedRoute.LockStartTime = TrainController->TTClockTime;
15835 // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
15836 // to use the new TruncateTrackVectorPosition & LockStartTime
15837  if(!AllRoutes->LockedRouteVector.empty())
15838  {
15839  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
15840  LRVIT++)
15841  {
15842  if(LRVIT->RouteNumber == RouteNumber)
15843  {
15844  LRVIT->TruncateTrackVectorPosition = LockedRoute.TruncateTrackVectorPosition;
15845  LRVIT->LockStartTime = LockedRoute.LockStartTime;
15846  ExistingLockedRouteModified = true;
15847  }
15848  }
15849  }
15850  if(!ExistingLockedRouteModified)
15851  AllRoutes->LockedRouteVector.push_back(LockedRoute);
15852  AllRoutes->SetAllRearwardsSignals(2, 0, RouteNumber, b);
15853  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
15854  // return all signals to red in route section to be truncated
15855  {
15856  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, RouteNumber).PrefDirVector.at(c);
15857  TTrackElement & TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
15858  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
15859  {
15860  TrackElement.Attribute = 0;
15861  Track->PlotSignal(2, TrackElement, Display);
15862  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
15863  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
15864  }
15865  }
15866 // Display->Update();//not needed as Clearand... called on return from GetAllRoutesTruncateElement in InterfaceUnit
15867  ReturnFlag = InRouteTrue;
15868  }
15869  else
15870  {
15871  AllRoutes->SetAllRearwardsSignals(3, 0, RouteNumber, b);
15872  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
15873  {
15874  AllRoutes->RemoveRouteElement(5, LastElementPtr(3)->HLoc, LastElementPtr(4)->VLoc, LastElementPtr(5)->ELink);
15875  ReturnFlag = InRouteTrue;
15876  }
15877  }
15878  AllRoutes->CheckMapAndRoutes(5); // test
15879  Utilities->CallLogPop(343);
15880  return;
15881  }
15882  }
15883  ReturnFlag = NotInRoute;
15884  Utilities->CallLogPop(344);
15885 }
15886 
15887 // ---------------------------------------------------------------------------
15889 /*
15890  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
15891  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
15892  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
15893  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
15894  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
15895  the route colours.
15896 */
15897 {
15898  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
15899  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
15901  int RouteNumber;
15902  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
15903  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
15904 
15905  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
15906  {
15907  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
15908  {
15909  if(PrefDirVector.at(x).TrackType == SignalPost)
15910  {
15911  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
15912  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
15913  }
15914  }
15915  AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0);
15916 // already set all signals to red in route so start at start of route for further rearwards signal setting
15917  }
15918  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
15919  {
15920  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
15921  }
15922  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
15923  AllRoutes->CheckMapAndRoutes(9); // test
15924  TrainController->BaseTime = TDateTime::CurrentDateTime();
15926  Utilities->CallLogPop(345);
15927  return;
15928 }
15929 
15930 // ---------------------------------------------------------------------------
15931 
15932 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
15933 /*
15934  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
15935 */
15936 {
15937  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
15938  AnsiString((short)PrefDirRoute));
15939  if(SearchVector.empty())
15940  {
15941  Utilities->CallLogPop(1149);
15942  return;
15943  }
15944  for(unsigned int b = 0; b < SearchVector.size(); b++)
15945  {
15948  PrefDirRoute);
15949  }
15950  Utilities->CallLogPop(346);
15951 }
15952 
15953 // ---------------------------------------------------------------------------
15954 
15955 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
15956 /*
15957  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
15958  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
15959  TOneRoute.
15960 */
15961 {
15962  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteAndLCChangeValues," + AnsiString((short)AutoSigsFlag) + "," +
15963  AnsiString((short)PrefDirRoute));
15964  RouteFlash.RouteFlashVector.clear();
15965  TRouteFlashElement RouteFlashElement;
15966 
15967  for(unsigned int b = 0; b < SearchVector.size(); b++)
15968  {
15969  int H = GetFixedSearchElementAt(11, b).HLoc;
15970  int V = GetFixedSearchElementAt(12, b).VLoc;
15972  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, PrefDirRoute);
15973  RouteFlashElement.HLoc = H;
15974  RouteFlashElement.VLoc = V;
15976  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
15977  }
15978  Utilities->CallLogPop(348);
15979 }
15980 
15981 // ---------------------------------------------------------------------------
15982 
15983 void TOneRoute::SetLCChangeValues(int Caller, bool PrefDirRoute) //used when setting routes to start any included LC's lowering
15984 {
15985  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)PrefDirRoute));
15986  if(!PrefDirVector.empty())
15987  {
15988  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
15989  {
15990  int H = PrefDirPtr->HLoc;
15991  int V = PrefDirPtr->VLoc;
15992  // check for any LCs that are closed to trains & set the flash values and store in the vector
15993  if(Track->IsLCAtHV(39, H, V))
15994  {
15995  if(Track->IsLCBarrierUpAtHV(0, H, V))
15996  {
15997  Track->LCChangeFlag = true;
15998  TTrack::TActiveLevelCrossing CLC; // constructor sets ReducedTimePenalty to false
15999  CLC.HLoc = H;
16000  CLC.VLoc = V;
16002  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
16005  if(PrefDirRoute)
16006  {
16007  CLC.TypeOfRoute = 1;
16008  }
16009  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
16010  Track->ChangingLCVector.push_back(CLC);
16011  }
16012  }
16013  }
16014  }
16015  Utilities->CallLogPop(1948);
16016 }
16017 
16018 // ---------------------------------------------------------------------------
16019 
16021 /*
16022  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
16023  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
16024  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
16025  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
16026 */
16027 {
16028  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
16029  if(!OverlayPlotted)
16030  {
16031  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
16032  {
16033  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
16034  continue;
16035  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
16036  Display->Update();
16037  }
16038  OverlayPlotted = true;
16039  }
16040  Utilities->CallLogPop(349);
16041 }
16042 
16043 // ---------------------------------------------------------------------------
16044 
16046 /*
16047  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
16048  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
16049  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
16050  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
16051 */
16052 {
16053  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
16054  if(OverlayPlotted)
16055  {
16056  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
16057  {
16058  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
16059  continue;
16060  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
16061  Display->Update();
16062  }
16063  OverlayPlotted = false;
16064  }
16065  Utilities->CallLogPop(350);
16066 }
16067 
16068 // ---------------------------------------------------------------------------
16069 
16070 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
16071 {
16072  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
16073  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
16074  {
16075  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
16076  }
16077  Utilities->CallLogPop(120);
16078  return AllRoutesVector.at(At);
16079 }
16080 
16081 // ---------------------------------------------------------------------------
16082 // ---------------------------------------------------------------------------
16083 
16085 {
16086  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
16087  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
16088  {
16089  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
16090  }
16091  Utilities->CallLogPop(121);
16092  return AllRoutesVector.at(At);
16093 }
16094 
16095 // ---------------------------------------------------------------------------
16096 
16097 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
16098 /*
16099  Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
16100 */
16101 {
16102  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
16103  for(unsigned int a = 0; a < AllRoutesSize(); a++)
16104  {
16105  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
16106  }
16107  Utilities->CallLogPop(351);
16108 }
16109 
16110 // ---------------------------------------------------------------------------
16111 
16112 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
16113 {
16114  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
16115  for(unsigned int a = 0; a < AllRoutesSize(); a++)
16116  {
16117  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
16118  }
16119  Utilities->CallLogPop(1706);
16120 }
16121 
16122 // ---------------------------------------------------------------------------
16123 
16124 bool TAllRoutes::GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
16125 /*
16126  Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is present in
16127  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
16128  Messages are given in GetRouteTruncateElement. If successful the route is truncated at and including
16129  the element that matches H & V. If PrefDirRoute ensure only truncate to a signal, else prevent
16130  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
16131  length (train length).
16132 */
16133 {
16134  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAllRoutesTruncateElement," + AnsiString(HLoc) + "," +
16135  AnsiString(VLoc) + "," + AnsiString((short)PrefDirRoute));
16136  for(unsigned int a = 0; a < AllRoutesSize(); a++)
16137  {
16138  TTruncateReturnType ReturnFlag;
16139  RouteTruncateFlag = true;
16140 // used in SetRearwardsSignalsReturnFalseForTrain (called by GetRouteTruncateElement) to skip continuation & buffer attribute change
16141  GetModifiableRouteAt(7, a).GetRouteTruncateElement(0, HLoc, VLoc, PrefDirRoute, ReturnFlag);
16142  RouteTruncateFlag = false;
16143  if(ReturnFlag == NotInRoute)
16144  continue;
16145  else if(ReturnFlag == InRouteTrue)
16146  {
16147  Utilities->CallLogPop(352);
16148  return true;
16149  }
16150  else if(ReturnFlag == InRouteFalse)
16151  {
16152  Utilities->CallLogPop(353);
16153  return false;
16154  }
16155  }
16156  Utilities->CallLogPop(354);
16157  return false;
16158 }
16159 
16160 // ---------------------------------------------------------------------------
16161 
16162 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
16163 /*
16164  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
16165  is found it returns true (for crossovers & points returns true whichever track the route is on), else returns false.
16166 */
16167 {
16168  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
16169  AnsiString(LinkPos));
16170  if(TrackVectorPosition == -1) // allows for continuation entries & exits
16171  {
16172  Utilities->CallLogPop(355);
16173  return false;
16174  }
16175  THVPair Route2MultiMapKeyPair;
16176 
16177  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
16178  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
16179  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
16180  TRoute2MultiMapIterator Route2MultiMapIterator;
16181 
16182  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
16183  {
16184  Utilities->CallLogPop(356);
16185  return false;
16186  }
16187  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
16188  {
16189  Utilities->CallLogPop(1422);
16190  return true;
16191  }
16192  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
16193  {
16194  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
16195 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
16196 // realised after writing this that can't be points as would have been covered above, but leave anyway
16197  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
16198  Route2MultiMapIterator->second.second);
16199  EntryLinkPos = PrefDirElement1.ELinkPos;
16200  ExitLinkPos = PrefDirElement1.XLinkPos;
16201  EntryLink = PrefDirElement1.Link[EntryLinkPos];
16202  ExitLink = PrefDirElement1.Link[ExitLinkPos];
16203  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
16204  {
16205  Utilities->CallLogPop(357);
16206  return true;
16207  }
16208  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
16209  {
16210  Utilities->CallLogPop(358);
16211  return true;
16212  }
16213  }
16214  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
16215  {
16216  Utilities->CallLogPop(1423);
16217  return true;
16218  }
16219  Utilities->CallLogPop(363);
16220  return false; // none found
16221 }
16222 
16223 // ---------------------------------------------------------------------------
16224 
16225 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
16226  Graphics::TBitmap* &EntryDirectionGraphicPtr)
16227 /*
16228  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
16229  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
16230  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
16231  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
16232  for replotting of AutoSigsRoutes.
16233 */
16234 {
16235  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
16236  AnsiString(LinkPos));
16237  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
16238  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
16239  if(TrackVectorPosition == -1)
16240  {
16241  Utilities->CallLogPop(364);
16242  return NoRoute; // allows for continuation entries & exits
16243  }
16244  THVPair Route2MultiMapKeyPair;
16245 
16246  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
16247  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
16248  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
16249  TRoute2MultiMapIterator Route2MultiMapIterator;
16250 
16251  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
16252  {
16253  Utilities->CallLogPop(365);
16254  return NoRoute; // none found
16255  }
16256  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
16257  {
16258  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
16259 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
16260  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
16261  Route2MultiMapIterator->second.second);
16262  EntryLinkPos = PrefDirElement1.ELinkPos;
16263  ExitLinkPos = PrefDirElement1.XLinkPos;
16264  EntryLink = PrefDirElement1.Link[EntryLinkPos];
16265  ExitLink = PrefDirElement1.Link[ExitLinkPos];
16266  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
16267  {
16268  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
16269  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
16270  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
16271  {
16272  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
16273  }
16274  if(PrefDirElement1.AutoSignals)
16275  {
16276  Utilities->CallLogPop(366);
16277  return AutoSigsRoute;
16278  }
16279  else
16280  {
16281  Utilities->CallLogPop(367);
16282  return NotAutoSigsRoute;
16283  }
16284  }
16285  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
16286  {
16287  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
16288  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
16289  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
16290  {
16291  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
16292  }
16293  if(PrefDirElement1.AutoSignals)
16294  {
16295  Utilities->CallLogPop(368);
16296  return AutoSigsRoute;
16297  }
16298  else
16299  {
16300  Utilities->CallLogPop(369);
16301  return NotAutoSigsRoute;
16302  }
16303  }
16304  }
16305  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
16306  {
16307  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
16308  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16309 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
16310  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
16311  EntryLinkPos = PrefDirElement2.ELinkPos;
16312  ExitLinkPos = PrefDirElement2.XLinkPos;
16313  EntryLink = PrefDirElement2.Link[EntryLinkPos];
16314  ExitLink = PrefDirElement2.Link[ExitLinkPos];
16315  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
16316  {
16317  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
16318  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
16319  {
16320  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
16321  }
16322  if(PrefDirElement2.AutoSignals)
16323  {
16324  Utilities->CallLogPop(370);
16325  return AutoSigsRoute;
16326  }
16327  else
16328  {
16329  Utilities->CallLogPop(371);
16330  return NotAutoSigsRoute;
16331  }
16332  }
16333  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
16334  {
16335  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
16336  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
16337  {
16338  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
16339  }
16340  if(PrefDirElement2.AutoSignals)
16341  {
16342  Utilities->CallLogPop(372);
16343  return AutoSigsRoute;
16344  }
16345  else
16346  {
16347  Utilities->CallLogPop(373);
16348  return NotAutoSigsRoute;
16349  }
16350  }
16351 
16352  ItPair.second--; // the second iterator points one past the last matching value
16353  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
16354  EntryLinkPos = PrefDirElement3.ELinkPos;
16355  ExitLinkPos = PrefDirElement3.XLinkPos;
16356  EntryLink = PrefDirElement3.Link[EntryLinkPos];
16357  ExitLink = PrefDirElement3.Link[ExitLinkPos];
16358  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
16359  {
16360  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
16361  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
16362  {
16363  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
16364  }
16365  if(PrefDirElement3.AutoSignals)
16366  {
16367  Utilities->CallLogPop(374);
16368  return AutoSigsRoute;
16369  }
16370  else
16371  {
16372  Utilities->CallLogPop(375);
16373  return NotAutoSigsRoute;
16374  }
16375  }
16376  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
16377  {
16378  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
16379  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
16380  {
16381  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
16382  }
16383  if(PrefDirElement3.AutoSignals)
16384  {
16385  Utilities->CallLogPop(376);
16386  return AutoSigsRoute;
16387  }
16388  else
16389  {
16390  Utilities->CallLogPop(377);
16391  return NotAutoSigsRoute;
16392  }
16393  }
16394  }
16395  Utilities->CallLogPop(378);
16396  return NoRoute; // none found
16397 }
16398 
16399 // ---------------------------------------------------------------------------
16400 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
16401 /*
16402  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
16403  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
16404 */
16405 {
16406  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
16407  AnsiString(LinkPos));
16408  if(TrackVectorPosition == -1)
16409  {
16410  RouteNumber = -1;
16411  Utilities->CallLogPop(379);
16412  return NoRoute; // allows for continuation & buffer entries & exits
16413  }
16414  THVPair Route2MultiMapKeyPair;
16415 
16416  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
16417  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
16418  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
16419  TRoute2MultiMapIterator Route2MultiMapIterator;
16420 
16421  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
16422  {
16423  RouteNumber = -1;
16424  Utilities->CallLogPop(380);
16425  return NoRoute; // none found
16426  }
16427  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
16428  {
16429  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
16430 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
16431  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
16432  Route2MultiMapIterator->second.second);
16433  EntryLinkPos = PrefDirElement1.ELinkPos;
16434  ExitLinkPos = PrefDirElement1.XLinkPos;
16435  EntryLink = PrefDirElement1.Link[EntryLinkPos];
16436  ExitLink = PrefDirElement1.Link[ExitLinkPos];
16437  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
16438  {
16439  RouteNumber = Route2MultiMapIterator->second.first;
16440  if(PrefDirElement1.AutoSignals)
16441  {
16442  Utilities->CallLogPop(381);
16443  return AutoSigsRoute;
16444  }
16445  else
16446  {
16447  Utilities->CallLogPop(382);
16448  return NotAutoSigsRoute;
16449  }
16450  }
16451  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
16452  {
16453  RouteNumber = Route2MultiMapIterator->second.first;
16454  if(PrefDirElement1.AutoSignals)
16455  {
16456  Utilities->CallLogPop(383);
16457  return AutoSigsRoute;
16458  }
16459  else
16460  {
16461  Utilities->CallLogPop(384);
16462  return NotAutoSigsRoute;
16463  }
16464  }
16465  }
16466  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
16467  {
16468  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
16469  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16470 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
16471  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
16472  EntryLinkPos = PrefDirElement2.ELinkPos;
16473  ExitLinkPos = PrefDirElement2.XLinkPos;
16474  EntryLink = PrefDirElement2.Link[EntryLinkPos];
16475  ExitLink = PrefDirElement2.Link[ExitLinkPos];
16476  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
16477  {
16478  RouteNumber = ItPair.first->second.first;
16479  if(PrefDirElement2.AutoSignals)
16480  {
16481  Utilities->CallLogPop(385);
16482  return AutoSigsRoute;
16483  }
16484  else
16485  {
16486  Utilities->CallLogPop(386);
16487  return NotAutoSigsRoute;
16488  }
16489  }
16490  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
16491  {
16492  RouteNumber = ItPair.first->second.first;
16493  if(PrefDirElement2.AutoSignals)
16494  {
16495  Utilities->CallLogPop(387);
16496  return AutoSigsRoute;
16497  }
16498  else
16499  {
16500  Utilities->CallLogPop(388);
16501  return NotAutoSigsRoute;
16502  }
16503  }
16504 
16505  ItPair.second--; // the second iterator points one past the last matching value
16506  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
16507  EntryLinkPos = PrefDirElement3.ELinkPos;
16508  ExitLinkPos = PrefDirElement3.XLinkPos;
16509  EntryLink = PrefDirElement3.Link[EntryLinkPos];
16510  ExitLink = PrefDirElement3.Link[ExitLinkPos];
16511  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
16512  {
16513  RouteNumber = ItPair.second->second.first;
16514  if(PrefDirElement3.AutoSignals)
16515  {
16516  Utilities->CallLogPop(389);
16517  return AutoSigsRoute;
16518  }
16519  else
16520  {
16521  Utilities->CallLogPop(390);
16522  return NotAutoSigsRoute;
16523  }
16524  }
16525  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
16526  {
16527  RouteNumber = ItPair.second->second.first;
16528  if(PrefDirElement3.AutoSignals)
16529  {
16530  Utilities->CallLogPop(391);
16531  return AutoSigsRoute;
16532  }
16533  else
16534  {
16535  Utilities->CallLogPop(392);
16536  return NotAutoSigsRoute;
16537  }
16538  }
16539  }
16540  RouteNumber = -1;
16541  Utilities->CallLogPop(393);
16542  return NoRoute; // none found
16543 }
16544 
16545 // ---------------------------------------------------------------------------
16546 
16547 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
16548 /*
16549  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
16550  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
16551  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
16552  and Route2MultiMap.
16553 */
16554 {
16555  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
16556  TOneRoute EmptyRoute;
16557 
16558  EmptyRoute.RouteID = NextRouteID;
16559  NextRouteID++;
16560 
16561  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
16562  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
16563  {
16564  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
16565  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
16566  }
16567  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
16568  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
16569 
16570  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
16571  Utilities->CallLogPop(394);
16572 }
16573 
16574 // ---------------------------------------------------------------------------
16575 
16577 /*
16578  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
16579  that is already in Route is used.
16580 */
16581 {
16582  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
16583  TOneRoute EmptyRoute;
16584 
16585  EmptyRoute.RouteID = Route->RouteID;
16586 
16587  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
16588  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
16589  {
16590  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
16591  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
16592  }
16593  Utilities->CallLogPop(1579);
16594 }
16595 
16596 // ---------------------------------------------------------------------------
16597 
16598 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
16599 /*
16600  When attaching a new route section to an existing route, it is sometimes necessary to erase the
16601  original route and create a new composite route. This function Erases all elements in the route
16602  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
16603  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
16604  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
16605  that are greater than the route number that is removed. The LockedRouteVector as also searched
16606  and if any relate to the route that has been cleared they are erased too, but the fact that one
16607  has been found is recorded so that it can be re-established later.
16608 */
16609 {
16610  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
16611  THVPair Route2MultiMapKeyPair;
16612  TRoute2MultiMapEntry Route2MultiMapEntry;
16613  TRoute2MultiMapIterator Route2MultiMapIterator;
16614 
16615 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
16616 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
16617 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
16618 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
16619 // If so the locked route is removed from the locked vector and is lost.
16620  LockedRouteTruncateTrackVectorPosition = 0;
16621  LockedRouteLastTrackVectorPosition = 0;
16622  LockedRouteLastXLinkPos = 0;
16623  LockedRouteLockStartTime = TDateTime(0);
16624  if(!LockedRouteVector.empty())
16625  {
16626  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
16627  {
16628  if(LRVIT->RouteNumber == RouteNumber)
16629  {
16630  LockedRouteTruncateTrackVectorPosition = LRVIT->TruncateTrackVectorPosition;
16631  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
16632  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
16633  LockedRouteLockStartTime = LRVIT->LockStartTime;
16634  LockedRouteFoundDuringRouteBuilding = true;
16635  LockedRouteVector.erase(LRVIT);
16636  }
16637  }
16638  }
16639 
16640  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
16641  {
16642  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
16643  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
16644  }
16645  Utilities->CallLogPop(395);
16646 }
16647 
16648 // ---------------------------------------------------------------------------
16649 
16651  TRoute2MultiMapIterator &Route2MultiMapIterator)
16652 /*
16653  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
16654  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
16655  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
16656  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
16657  are given for failure.
16658 */
16659 {
16660  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
16661  AnsiString(VLoc) + "," + AnsiString(ELink));
16662  TRouteElementPair ReturnPair;
16663 
16664  ReturnPair.first = -1;
16665  ReturnPair.second = 0;
16666  THVPair Route2MultiMapKeyPair;
16667 
16668  Route2MultiMapKeyPair.first = HLoc;
16669  Route2MultiMapKeyPair.second = VLoc;
16670  TRoute2MultiMapEntry Route2MultiMapEntry;
16671 
16672  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
16673  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
16674 
16675  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16676  Route2MultiMapIterator = ItPair.first;
16677 
16678  if(ItPair.first == ItPair.second)
16679  {
16680  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
16681  }
16682 
16683  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
16684  {
16685  ReturnPair.first = ItPair.first->second.first;
16686  ReturnPair.second = ItPair.first->second.second;
16687  Route2MultiMapIterator = ItPair.first;
16688  Utilities->CallLogPop(396);
16689  return ReturnPair;
16690  }
16691  ItPair.first++;
16692  if(ItPair.first == ItPair.second)
16693  {
16694  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
16695  }
16696  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
16697  {
16698  ReturnPair.first = ItPair.first->second.first;
16699  ReturnPair.second = ItPair.first->second.second;
16700  Route2MultiMapIterator = ItPair.first;
16701  Utilities->CallLogPop(397);
16702  return ReturnPair;
16703  }
16704  Utilities->CallLogPop(398);
16705  return ReturnPair;
16706 }
16707 
16708 // ---------------------------------------------------------------------------
16709 
16710 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
16711 /*
16712  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
16713  Examines Route2MultiMap and returns true if oa route is found with the passed values of H, V and ELink.
16714  RouteNumber (route position in AllRoutes vector is returned as a reference.
16715  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
16716  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
16717 */
16718 {
16719  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
16720  AnsiString(VLoc) + "," + AnsiString(ELink));
16721  THVPair Route2MultiMapKeyPair;
16722 
16723  Route2MultiMapKeyPair.first = HLoc;
16724  Route2MultiMapKeyPair.second = VLoc;
16725  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
16726 
16727  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16728 
16729  if(ItPair.first == ItPair.second)
16730  {
16731  RouteNumber = -1;
16732  Utilities->CallLogPop(2032);
16733  return false;
16734  }
16735 
16736  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
16737  {
16738  RouteNumber = ItPair.first->second.first;
16739  Utilities->CallLogPop(2033);
16740  return true;
16741  }
16742 
16743  ItPair.first++;
16744 
16745  if(ItPair.first == ItPair.second)
16746  {
16747  RouteNumber = -1;
16748  Utilities->CallLogPop(2034);
16749  return false;
16750  }
16751 
16752  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
16753  {
16754  RouteNumber = ItPair.first->second.first;
16755  Utilities->CallLogPop(2035);
16756  return true;
16757  }
16758  RouteNumber = -1;
16759  Utilities->CallLogPop(2036);
16760  return false;
16761 }
16762 
16763 // ---------------------------------------------------------------------------
16764 
16765 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
16766 /*
16767  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
16768  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
16769  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
16770  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
16771  Called by TAllRoutes::AddRouteElement.
16772 */
16773 {
16774  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
16775  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
16776  THVPair Route2MultiMapKeyPair;
16777 
16778  Route2MultiMapKeyPair.first = HLoc;
16779  Route2MultiMapKeyPair.second = VLoc;
16780  TRoute2MultiMapEntry Route2MultiMapEntry;
16781 
16782  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
16783  TRouteElementPair RouteElementPair;
16784 
16785  RouteElementPair.first = RouteNumber;
16786  RouteElementPair.second = RouteElementNumber;
16787  Route2MultiMapEntry.second = RouteElementPair;
16788 
16789  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
16790  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
16791  {
16792  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
16793  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
16794  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
16795  {
16796  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
16797  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
16798  {
16799  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
16800  }
16801  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
16802  }
16803  else
16804  // same ELink so have an error
16805  {
16806  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
16807  }
16808  }
16809  else
16810  Route2MultiMap.insert(Route2MultiMapEntry);
16811 // element at H&V not found in map so insert it
16812  Utilities->CallLogPop(399);
16813 }
16814 
16815 // ---------------------------------------------------------------------------
16816 
16818 /*
16819  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
16820  and the second in the reference SecondPair. If there's only one then it's the function return
16821 */
16822 {
16823  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
16824  AnsiString(VLoc));
16826 
16827  TempPair.first = -1;
16828  TempPair.second = 0;
16829  SecondPair = TempPair;
16830  TRoute2MultiMapIterator Route2MultiMapIterator;
16831  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
16832  THVPair Route2MultiMapKeyPair;
16833 
16834  Route2MultiMapKeyPair.first = HLoc;
16835  Route2MultiMapKeyPair.second = VLoc;
16836  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
16837  {
16838  Utilities->CallLogPop(400);
16839  return TempPair;
16840  }
16841  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
16842  {
16843  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
16844  Utilities->CallLogPop(401);
16845  return Route2MultiMapIterator->second;
16846  }
16847  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
16848  {
16849  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16850  TempPair = ItRange.first->second;
16851  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
16852  Utilities->CallLogPop(402);
16853  return TempPair;
16854  }
16855  Utilities->CallLogPop(403);
16856  return TempPair;
16857 }
16858 
16859 // ---------------------------------------------------------------------------
16860 
16861 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
16862 /*
16863  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
16864  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
16865 */
16866 {
16867  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
16868  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16869  {
16870  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
16871  {
16872  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
16873  TAllRoutes::TRouteElementPair SecondPair;
16874  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
16875  if(RouteElementPair.first == -1)
16876  // failed to find element in multimap
16877  {
16878  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
16879  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
16880  }
16881  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
16882  // neither pair has expected route number
16883  {
16884  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
16885  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
16886  (AnsiString)Caller);
16887  }
16888  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
16889  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
16890  {
16891  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
16892  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
16893  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
16894  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
16895  }
16896  }
16897  }
16898  unsigned int SizeVal = 0;
16899 
16900 // check map and sum of route sizes match
16901  for(unsigned int a = 0; a < AllRoutesSize(); a++)
16902  {
16903  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
16904  }
16905  if(SizeVal != Route2MultiMap.size())
16906  {
16907  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
16908  (AnsiString)Caller);
16909  }
16910  Utilities->CallLogPop(404);
16911  return;
16912 }
16913 
16914 // ---------------------------------------------------------------------------
16915 
16916 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
16917 /*
16918  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
16919  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
16920  exceed that for the erased route. Where this is so the RouteNumber is decremented.
16921 */
16922 {
16923  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
16924  if(!Route2MultiMap.empty())
16925  {
16926  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
16927  {
16928  if(Route2MultiMapIterator->second.first > RouteNumber)
16929  Route2MultiMapIterator->second.first--;
16930  }
16931  }
16932  Utilities->CallLogPop(405);
16933 }
16934 
16935 // ---------------------------------------------------------------------------
16936 
16937 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
16938 /*
16939  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
16940  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
16941  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
16942 */
16943 {
16944  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
16945  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
16946  if(!Route2MultiMap.empty())
16947  {
16948  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
16949  {
16950  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
16951  Route2MultiMapIterator->second.second--;
16952  }
16953  }
16954  Utilities->CallLogPop(406);
16955 }
16956 
16957 // ---------------------------------------------------------------------------
16958 
16959 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
16960 /*
16961  Erases the route element from Route2MultiMap and from the PrefDirVector.
16962  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
16963  decremented if they are greater than the element number removed, and if the entire route is removed
16964  then the route numbers are also decremented in the map for route numbers that are greater than the route
16965  number that is removed.
16966 */
16967 {
16968  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
16969  AnsiString(ELink));
16970  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
16971  TRoute2MultiMapIterator Route2MultiMapIterator;
16972 
16973  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
16974  if(RequiredRoutePair.first == -1)
16975  {
16976  throw Exception("Failed to find route element in RemoveRouteElement");
16977  }
16978  Route2MultiMap.erase(Route2MultiMapIterator);
16979  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
16980 
16981 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
16982  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
16983 
16984  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
16985  {
16986  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
16987  }
16988 
16989 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
16990 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
16991 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
16992 // to check if a route element is present, and the element has already been removed from the map - see above.
16993 
16994 // before erase the element check if it's in a locked route, and if so change the TruncateTrackVectorPosition to the next valid (XLinkPos] element position
16995 /*
16996  int LockedVectorNumber = -1;
16997  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
16998  {
16999  LockedRouteVector.at(LockedVectorNumber).TruncateTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
17000  }
17001 */
17002 
17003 // erase element from route
17004  GetModifiableRouteAt(8, RequiredRoutePair.first).EraseRouteElementAt(&(GetModifiableRouteAt(9, RequiredRoutePair.first).GetModifiablePrefDirElementAt(1,
17005  RequiredRoutePair.second)));
17006 // CheckMapAndRoutes();//test - drop - tested below
17007 
17008 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
17009 // be so as continuation exit is at the end of the route, and truncation is from the end
17011  {
17013  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
17014  AutoSigVectorIT--)
17015  {
17016  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
17017  {
17018  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
17019  }
17020  }
17021  }
17022 
17023 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
17024 // and adjust all the corresponding route numbers
17025  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
17026  {
17027  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
17028  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
17029  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
17030 
17031 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
17032  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
17033  it is erased then - see TInterface::ApproachLocking
17034 
17035  if(LockedVectorNumber > -1)
17036  {
17037  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
17038  }
17039 */
17040  // decrement route numbers in the locked route vector whether or not this route is a locked route
17041  if(!LockedRouteVector.empty())
17042  {
17043  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
17044  {
17045  if(LRVIT->RouteNumber > RequiredRoutePair.first)
17046  {
17047  LRVIT->RouteNumber--;
17048  }
17049  }
17050  }
17051 
17053  {
17055  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
17056  AutoSigVectorIT--)
17057  {
17058  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
17059  AutoSigVectorIT->RouteNumber--;
17060  }
17061  }
17062  }
17063  CheckMapAndRoutes(7); // test
17064  Utilities->CallLogPop(407);
17065 }
17066 
17067 // ---------------------------------------------------------------------------
17068 
17069 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
17070 /*
17071  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
17072  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
17073  since that catches all route elements wherever created
17074 */
17075 {
17076  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
17077  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
17078  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
17079  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1);
17080  Utilities->CallLogPop(408);
17081 }
17082 
17083 // ---------------------------------------------------------------------------
17084 
17085 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
17086 /*
17087  Enter with signal at TrackVectorElement already set to red by the passing train.
17088  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
17089  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
17090  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
17091  case the function sets no further signals.
17092 */
17093 {
17094  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
17095  "," + AnsiString(XLinkPos));
17096  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
17097  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
17098 
17099  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
17100  if(RouteElementPair.first == -1)
17101  {
17102  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
17103  }
17104  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
17105 
17106  RequiredPair = RouteElementPair;
17107  if(RouteElement.XLinkPos != XLinkPos)
17108  {
17109  if(SecondPair.first != -1)
17110  {
17111  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
17112  RequiredPair = SecondPair;
17113  if(RouteElement.XLinkPos != XLinkPos)
17114  {
17115  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
17116  }
17117  }
17118  else
17119  {
17120  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
17121  }
17122  }
17123 
17124 // new function
17125  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
17126  Utilities->CallLogPop(409);
17127 }
17128 
17129 // ---------------------------------------------------------------------------
17130 
17131 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
17132 /*
17133  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
17134  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
17135  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
17136  accordingly, then double yellow, then green. There are only 3 calls in all for any given route, and the AccessNumber changes from 0 to 1
17137  to 2 for successive calls.
17138  Initially Attribute is set to AccessNumber + 1 to correspond to the first signal attribute to be set, then a number of validity checks
17139  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
17140  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
17141  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals.
17142 */
17143 {
17144  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
17145  AnsiString(AccessNumber));
17146  TPrefDirElement RouteElement;
17147  int Attribute = AccessNumber + 1;
17148 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
17149  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
17150 
17151  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
17152  {
17153  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
17154  }
17155  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
17156  {
17157  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
17158  }
17159  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
17160  x).XLinkPos] != End)
17161  {
17162  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
17163  }
17164 // new function
17165  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
17166  Utilities->CallLogPop(410);
17167 }
17168 
17169 // ---------------------------------------------------------------------------
17170 
17171 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
17172 /*
17173  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
17174  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
17175  or (b) in a linked rear route, in which case the function sets no further signals.
17176 
17177  First call SetRearwardsSignalsReturnFalseForTrain (which is only called by this function) to set signals in route RouteNumber according
17178  to the received or modified (because of the forward look for buffers or continuation) Attribute. If no train is found during this call
17179  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrain for each rearwards linked route until either reach the
17180  beginning of the last linked route or find a train on a linked rear route. If no train was found during the RouteNumber call to
17181  SetRearwardsSignalsReturnFalseForTrain then the function terminates here.
17182  However if a train was found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrain then need to continue after the
17183  train in case had just added a route segment behind a train that now forms part of a single continuous route, otherwise the signals
17184  won't be set behind the train. First the route is examined element by element from the RouteStartPosition towards the start of the
17185  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
17186  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
17187  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
17188  found behind the train.
17189 
17190  Description of SetRearwardsSignalsReturnFalseForTrain for reference:
17191  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
17192  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
17193  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
17194  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
17195  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
17196  a route.
17197 
17198  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
17199  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
17200  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 and continue working backwards
17201  for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
17202  reference. If no train is found before the beginning of the route is reached the function returns true.
17203 
17204 */
17205 {
17206  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
17207  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
17208  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
17209  int RearwardLinkedRouteNumber;
17210 
17211  Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes
17212  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrain(1, Attribute, RouteStartPosition)) // updates Attribute to 1+ final
17213  // signal value in the route for use in further linked routes
17214  {
17215  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1
17216  {
17217  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
17218  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
17219  {
17220  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrain(2, Attribute, AllRoutes->GetFixedRouteAt(130,
17221  RearwardLinkedRouteNumber).PrefDirSize() - 1)))
17222  break;
17223  // in above the RouteSettingFlag is set to false because this call is for routes that lie behind the route that is being set so don't want to
17224  // flash LCs on those routes
17225  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
17226  }
17227  }
17228  }
17229  else
17230  // found a train in the entry route before the beginning of the route, so need to continue after the train in case had just added a
17231  // route segment behind a train that now forms part of a single continuous route, otherwise the signals won't be set behind the train
17232  {
17233  int TrainID, TrainPosition, BehindTrainPosition;
17234  bool FoundTrain = false, BehindTrain = false;
17235  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
17236  {
17237  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
17238  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
17239  TrainID = TrackElement.TrainIDOnElement;
17240  if(TrackElement.TrackType == Bridge)
17241  {
17242  if(PrefDirElement.XLinkPos < 2)
17243  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
17244  else
17245  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
17246  }
17247  if(TrainID == -1)
17248  continue;
17249  else
17250  {
17251  FoundTrain = true;
17252  TrainPosition = x;
17253  break;
17254  }
17255  }
17256  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then no route behind the train so can stop
17257  {
17258  for(int x = TrainPosition; x >= 0; x--) // then step back from that position until find element behind the train - ignore any
17259  // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
17260  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
17261  // need the element behind the rearmost train.
17262  {
17263  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
17264  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
17265  TrainID = TrackElement.TrainIDOnElement;
17266  if(TrackElement.TrackType == Bridge)
17267  {
17268  if(PrefDirElement.XLinkPos < 2)
17269  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
17270  else
17271  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
17272  }
17273  if(TrainID != -1)
17274  continue; // still on train
17275  else
17276  {
17277  BehindTrain = true;
17278  BehindTrainPosition = x;
17279  break;
17280  }
17281  }
17282  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
17283  // so on for as many trains as there are on the single route
17284  {
17285  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // false because can't set a route where there is a train
17286  // first signal behind train to be red
17287  }
17288  }
17289  }
17290  Utilities->CallLogPop(411);
17291 }
17292 
17293 // ---------------------------------------------------------------------------
17294 
17295 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
17296 {
17297 /* Locked if a train moving in the direction of the route within 3 signals back from truncate point (on the route itself or any linked routes, or on the element
17298  immediately before the start of the route or linked route - this because train cancels route elements that it touches) unless
17299  first signal is red, then OK
17300 */
17301  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
17302  AnsiString(RouteTruncatePosition));
17303  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber, StartPosition = RouteTruncatePosition;
17304  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
17305  TPrefDirElement PrefDirElement, FirstElement;
17306  TTrackElement TrackElement;
17307  bool ExamineRoute = true;
17308 
17309  while(ExamineRoute)
17310  {
17311  for(int x = StartPosition; x >= 0; x--) //work back along the route from the truncate point
17312  {
17313  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
17314  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
17315  TrainID = TrackElement.TrainIDOnElement;
17316  if(TrackElement.TrackType == Bridge)
17317  {
17318  if(PrefDirElement.XLinkPos < 2)
17319  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
17320  else
17321  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
17322  }
17323  if(TrainID > -1)
17324  {
17325  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
17326  { //any trains further back in route will be protected by the red signal behind the stopped train
17327  Utilities->CallLogPop(412);
17328  return false;
17329  }
17330  //added after v2.4.1 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
17331  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
17332  //other way & can cancel the route
17333  {
17334  Utilities->CallLogPop(2203);
17335  return false;
17336  }
17337  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
17338  return true; //TrainOccupyingRoute which is outside this function but also causes route locking)
17339  }
17340  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
17341  {
17342  if(TrackElement.Attribute == 0)
17343  {
17344  Utilities->CallLogPop(413);
17345  return false; // OK, red signal in front of a train
17346  }
17347  SignalCount++;
17348  if(SignalCount >= 3)
17349  {
17350  Utilities->CallLogPop(414);
17351  return false;
17352  }
17353  }
17354  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
17355  // ElinkPos because working back along PrefDir to beginning
17356  {
17357  Utilities->CallLogPop(415);
17358  return false; // test - set to true to create a locked buffer-ended route, false for normal use
17359  }
17360  }
17361  //now look at linked rearwards routes
17362  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
17363  StartPosition = CurrentRoute.PrefDirSize() - 1;
17364  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
17365  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
17366  {
17367  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
17368  ExamineRoute = true;
17369  StartPosition = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
17370  }
17371  else
17372  {
17373  // here check for a train on the element immediately before the first route element
17374  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
17375  TrainID = PriorTrackElement.TrainIDOnElement;
17376  if(PriorTrackElement.TrackType == Bridge)
17377  {
17378  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
17379  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos01;
17380  else
17381  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos23;
17382  }
17383  if(TrainID > -1)
17384  {
17385  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
17386  {
17387  Utilities->CallLogPop(748);
17388  return false;
17389  }
17390  //added after v2.4.1 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
17391  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
17392  //other way & can cancel the route
17393  {
17394  Utilities->CallLogPop(2204);
17395  return false;
17396  }
17397  Utilities->CallLogPop(1962);
17398  return true; //otherwise need to lock the route
17399  }
17400  ExamineRoute = false;
17401  }
17402  }
17403 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
17404 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
17405  Utilities->CallLogPop(416);
17406  return false;
17407 }
17408 
17409 // ---------------------------------------------------------------------------
17410 
17411 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
17412  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
17413 {
17414  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
17415  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
17416  TPrefDirElement InternalPrefDirElement; // blank element
17417 
17418  PrefDirElement = InternalPrefDirElement;
17419  if(LockedRouteVector.empty())
17420  {
17421  Utilities->CallLogPop(417);
17422  return false;
17423  }
17424 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
17425 // even if some elements have been removed from the front by a train
17426  bool InLockedRoute = false;
17427 
17428  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
17429  {
17430  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
17431  { // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
17432  // doesn't arise)
17433  InLockedRoute = true;
17434  break;
17435  }
17436  }
17437  if(!InLockedRoute)
17438  {
17439  Utilities->CallLogPop(418);
17440  return false;
17441  }
17442 
17443  int RouteNumber, VectorCount = 0;
17444  TRouteType RouteType;
17445 
17446  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
17447  {
17448  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
17449  if(RouteType == NoRoute)
17450  continue;
17451  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
17452  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
17453  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
17454  {
17455  throw Exception
17456  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
17457  }
17458  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
17459  {
17460  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
17461  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->TruncateTrackVectorPosition)
17462  {
17463  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
17464  {
17465  PrefDirElement = InternalPrefDirElement;
17466  LockedVectorNumber = VectorCount;
17467  Utilities->CallLogPop(419);
17468  return true;
17469  }
17470  }
17471  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->TruncateTrackVectorPosition)
17472  {
17473  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
17474  {
17475  PrefDirElement = InternalPrefDirElement;
17476  LockedVectorNumber = VectorCount;
17477  Utilities->CallLogPop(420);
17478  return true;
17479  }
17480  else
17481  break; // reached & tested LRVIT->TruncateTrackVectorPosition for a match so don't want to go any further for this route
17482  }
17483  }
17484  VectorCount++;
17485  }
17486  Utilities->CallLogPop(421);
17487  return false;
17488 }
17489 
17490 // ---------------------------------------------------------------------------
17491 
17493 {
17494  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
17495  for(unsigned int x = 0; x < AllRoutesSize(); x++)
17496  {
17497  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
17498  {
17499  Utilities->CallLogPop(963);
17500  return x;
17501  }
17502  }
17503  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
17504 }
17505 
17506 // ---------------------------------------------------------------------------
17507 
17509  // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
17510  // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
17511 {
17512  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
17513  for(unsigned int x = 0; x < AllRoutesSize(); x++)
17514  {
17515  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
17516  {
17517  Utilities->CallLogPop(2039);
17518  return true;
17519  }
17520  }
17521  Utilities->CallLogPop(2040);
17522  return false;
17523 }
17524 
17525 // ---------------------------------------------------------------------------
17526 
17528 {
17529  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
17530  for(unsigned int x = 0; x < AllRoutesSize(); x++)
17531  {
17532  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
17533  {
17534  Utilities->CallLogPop(964);
17535  return GetFixedRouteAt(159, x);
17536  }
17537  }
17538  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
17539 }
17540 
17541 // ---------------------------------------------------------------------------
17542 
17544 {
17545  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
17546  for(unsigned int x = 0; x < AllRoutesSize(); x++)
17547  {
17548  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
17549  {
17550  Utilities->CallLogPop(965);
17551  return GetModifiableRouteAt(15, x);
17552  }
17553  }
17554  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
17555 }
17556 
17557 // ---------------------------------------------------------------------------
17558 
17559 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
17560 {
17561  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
17562  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
17563  Utilities->SaveFileInt(OutFile, NextRouteID);
17564  for(unsigned int x = 0; x < AllRoutesSize(); x++)
17565  {
17566  TOneRoute OneRoute = GetFixedRouteAt(165, x);
17567  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
17568  OneRoute.SavePrefDirVector(6, OutFile);
17569  }
17570  Utilities->CallLogPop(1442);
17571 }
17572 
17573 // ---------------------------------------------------------------------------
17574 
17575 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
17576 {
17577  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
17578  int NumberOfRoutes;
17579 
17580  NumberOfRoutes = Utilities->LoadFileInt(InFile);
17581  NextRouteID = Utilities->LoadFileInt(InFile);
17582  for(int x = 0; x < NumberOfRoutes; x++)
17583  {
17584  TOneRoute OneRoute; // empty route
17585  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
17586  OneRoute.LoadPrefDir(2, InFile);
17588  {
17589  StoreOneRouteAfterSessionLoad(0, &OneRoute);
17590  }
17591  else
17592  {
17593  Utilities->CallLogPop(1443);
17594  return false;
17595  }
17596  }
17597  Utilities->CallLogPop(1444);
17598  return true;
17599 }
17600 
17601 // ---------------------------------------------------------------------------
17602 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
17603 {
17604  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
17605  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
17606 
17607  if((NumberOfRoutes < 0) || (NumberOfRoutes > 5000))
17608  {
17609  Utilities->CallLogPop(1445);
17610  return false;
17611  }
17612  int NextID = Utilities->LoadFileInt(InFile);
17613 
17614  if((NextID < 0) || (NextID > 1000000))
17615  {
17616  Utilities->CallLogPop(1446);
17617  return false;
17618  }
17619  for(int x = 0; x < NumberOfRoutes; x++)
17620  {
17621  int RouteID = Utilities->LoadFileInt(InFile);
17622  if((RouteID < 0) || (RouteID > 20000))
17623  {
17624  Utilities->CallLogPop(1447);
17625  return false;
17626  }
17627  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
17628  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
17629  {
17630  Utilities->CallLogPop(1448);
17631  return false;
17632  }
17633  }
17634  Utilities->CallLogPop(1449);
17635  return true;
17636 }
17637 
17638 // ---------------------------------------------------------------------------
17639 
17640 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
17641 { // return true for a loop
17642  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
17643  AnsiString(StartPosition));
17644  if(EndPosition == StartPosition)
17645  {
17646  Utilities->CallLogPop(1839);
17647  return true; // shouldn't happen but treat as a loop if does
17648  }
17649 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
17650  int TVPos = EndPosition; //TVPos is the current element and NewTVPos is the element it connects to
17651  int LkPos = EndXLinkPos; //LkPos is the exit link and NewLkPos is the entry link of the linked element
17652 
17653  while(TrackIsInARoute(15, TVPos, LkPos))
17654  {
17655  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos]; //see above
17656  int NewLkPos = -1;
17657  if(NewTVPos > -1)
17658  {
17659  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
17660  if(NewLkPos == -1)
17661  {
17662  Utilities->CallLogPop(1840);
17663  return true; // shouldn't arise but treat as loop if does
17664  }
17665  }
17666  else // reached a buffer or continuation
17667  {
17668  Utilities->CallLogPop(1841);
17669  return false;
17670  }
17671 //Error found by Xeon notified by email 13/10/20.
17672 //Need to make sure there is a route with the new entry link NewLkPos on the next element (TrackIsInARoute normally used where it doesn't matter which track a route
17673 //is on - except for bridges). But here a route can end at a trailing point leg or a crossover and if so it doesn't link to the route on the other track, and needs to
17674 //return false. Without the new check below the program gets stuck in an endless loop, which is the error that Xeon found.
17675 //If there isn't a route at all on the next element then it would return false at the next iteration so can return false here.
17676 //New check added for v2.6.0
17677 //Note: Could probably use GetRouteTypeAndNumber in place of TrackIsInARoute in the while statement above and dispense with this new check, but I prefer to keep mods as simple
17678 //as possible in case there are other unforeseen effects.
17679  int RouteNumber; //dummy, not used
17680  if(GetRouteTypeAndNumber(36, NewTVPos, NewLkPos, RouteNumber) == NoRoute)
17681  {
17682  Utilities->CallLogPop(2241);
17683  return false;
17684  }
17685  //now make the connected element the current element, read across the TV number and determine the exit link
17686  TVPos = NewTVPos;
17687  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
17688  {
17689  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
17690  {
17691  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
17692  LkPos = 1;
17693  else
17694  LkPos = 3;
17695  }
17696  else
17697  LkPos = 0;
17698  }
17699  else
17700  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
17701  if(TVPos == StartPosition)
17702  {
17703  Utilities->CallLogPop(1842);
17704  return true; // it is a loop
17705  }
17706  }
17707  Utilities->CallLogPop(1843);
17708  return false; // reached end of route so not a loop
17709 }
17710 
17711 // ---------------------------------------------------------------------------
17712 
17713 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
17714 /*
17715  Track geometry allows diagonals to cross without occupying the same track element, so when
17716  route plotting it is necessary to check if there is an existing route or a train on such a crossing
17717  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
17718  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
17719  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
17720  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
17721  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
17722  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
17723  Each of these is examined in turn for each route element in the relevant position.
17724 
17725  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
17726  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
17727  that returns false in all cases (including elements & links not present) except train present.
17728 */
17729 {
17730  int TrainID; // not used in this function
17731 
17732  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
17733  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
17734  TPrefDirElement TempPrefDirElement;
17735  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
17736 
17737  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
17738  if(FirstPair.first > -1)
17739  {
17740  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
17741  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17742  {
17743  Utilities->CallLogPop(310);
17744  return true;
17745  }
17746  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17747  {
17748  Utilities->CallLogPop(311);
17749  return true;
17750  }
17751  }
17752  if(SecondPair.first > -1)
17753  {
17754  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
17755  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17756  {
17757  Utilities->CallLogPop(312);
17758  return true;
17759  }
17760  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17761  {
17762  Utilities->CallLogPop(313);
17763  return true;
17764  }
17765  }
17766 
17767  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
17768  9, TrainID)))
17769  {
17770  Utilities->CallLogPop(1997);
17771  return true;
17772  }
17773 
17774  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
17775  if(FirstPair.first > -1)
17776  {
17777  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
17778  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17779  {
17780  Utilities->CallLogPop(314);
17781  return true;
17782  }
17783  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17784  {
17785  Utilities->CallLogPop(315);
17786  return true;
17787  }
17788  }
17789  if(SecondPair.first > -1)
17790  {
17791  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
17792  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17793  {
17794  Utilities->CallLogPop(316);
17795  return true;
17796  }
17797  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17798  {
17799  Utilities->CallLogPop(317);
17800  return true;
17801  }
17802  }
17803 
17804  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
17805  9, TrainID)))
17806  {
17807  Utilities->CallLogPop(1998);
17808  return true;
17809  }
17810 
17811  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
17812  if(FirstPair.first > -1)
17813  {
17814  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
17815  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17816  {
17817  Utilities->CallLogPop(318);
17818  return true;
17819  }
17820  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17821  {
17822  Utilities->CallLogPop(319);
17823  return true;
17824  }
17825  }
17826  if(SecondPair.first > -1)
17827  {
17828  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
17829  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17830  {
17831  Utilities->CallLogPop(320);
17832  return true;
17833  }
17834  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17835  {
17836  Utilities->CallLogPop(321);
17837  return true;
17838  }
17839  }
17840 
17841  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
17842  7, TrainID)))
17843  {
17844  Utilities->CallLogPop(1999);
17845  return true;
17846  }
17847 
17848  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
17849  if(FirstPair.first > -1)
17850  {
17851  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
17852  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17853  {
17854  Utilities->CallLogPop(322);
17855  return true;
17856  }
17857  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17858  {
17859  Utilities->CallLogPop(323);
17860  return true;
17861  }
17862  }
17863  if(SecondPair.first > -1)
17864  {
17865  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
17866  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17867  {
17868  Utilities->CallLogPop(324);
17869  return true;
17870  }
17871  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17872  {
17873  Utilities->CallLogPop(325);
17874  return true;
17875  }
17876  }
17877 
17878  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
17879  3, TrainID)))
17880  {
17881  Utilities->CallLogPop(2000);
17882  return true;
17883  }
17884 
17885  Utilities->CallLogPop(326);
17886  return false;
17887 }
17888 
17889 // ---------------------------------------------------------------------------
17890 
17891 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
17892 /*
17893  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
17894  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
17895  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
17896  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
17897  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
17898  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
17899  Each of these is examined in turn for each route element in the relevant position.
17900 */
17901 {
17902  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
17903  "," + AnsiString(DiagonalLinkNumber));
17904  TPrefDirElement TempPrefDirElement;
17905  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
17906 
17907  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
17908  if(FirstPair.first > -1)
17909  {
17910  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
17911  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17912  {
17913  Utilities->CallLogPop(2010);
17914  return true;
17915  }
17916  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17917  {
17918  Utilities->CallLogPop(2011);
17919  return true;
17920  }
17921  }
17922  if(SecondPair.first > -1)
17923  {
17924  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
17925  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17926  {
17927  Utilities->CallLogPop(2012);
17928  return true;
17929  }
17930  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17931  {
17932  Utilities->CallLogPop(2013);
17933  return true;
17934  }
17935  }
17936 
17937  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
17938  if(FirstPair.first > -1)
17939  {
17940  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
17941  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17942  {
17943  Utilities->CallLogPop(2014);
17944  return true;
17945  }
17946  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17947  {
17948  Utilities->CallLogPop(2015);
17949  return true;
17950  }
17951  }
17952  if(SecondPair.first > -1)
17953  {
17954  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
17955  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17956  {
17957  Utilities->CallLogPop(2016);
17958  return true;
17959  }
17960  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17961  {
17962  Utilities->CallLogPop(2017);
17963  return true;
17964  }
17965  }
17966 
17967  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
17968  if(FirstPair.first > -1)
17969  {
17970  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
17971  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17972  {
17973  Utilities->CallLogPop(2018);
17974  return true;
17975  }
17976  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17977  {
17978  Utilities->CallLogPop(2019);
17979  return true;
17980  }
17981  }
17982  if(SecondPair.first > -1)
17983  {
17984  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
17985  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17986  {
17987  Utilities->CallLogPop(2020);
17988  return true;
17989  }
17990  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17991  {
17992  Utilities->CallLogPop(2021);
17993  return true;
17994  }
17995  }
17996 
17997  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
17998  if(FirstPair.first > -1)
17999  {
18000  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
18001  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
18002  {
18003  Utilities->CallLogPop(2022);
18004  return true;
18005  }
18006  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
18007  {
18008  Utilities->CallLogPop(2023);
18009  return true;
18010  }
18011  }
18012  if(SecondPair.first > -1)
18013  {
18014  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
18015  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
18016  {
18017  Utilities->CallLogPop(2024);
18018  return true;
18019  }
18020  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
18021  {
18022  Utilities->CallLogPop(2025);
18023  return true;
18024  }
18025  }
18026 
18027  Utilities->CallLogPop(2026);
18028  return false;
18029 }
18030 
18031 // ---------------------------------------------------------------------------
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:7645
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:677
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:477
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:16162
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1185
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:916
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:464
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:10377
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:663
TRailGraphics::LCLHSVerMan
Graphics::TBitmap * LCLHSVerMan
Definition: GraphicUnit.h:730
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:613
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:565
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:10350
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:351
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:485
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:80
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:353
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:875
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:4930
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:11832
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:772
TFixedTrackPiece
Definition: TrackUnit.h:80
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:107
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1586
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:182
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:699
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:408
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:907
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:6700
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:16765
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:90
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:791
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:246
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:908
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:9037
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:793
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:17171
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:919
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1243
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:509
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:691
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:581
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:702
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:12091
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:759
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:620
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:706
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:349
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:11872
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:679
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3579
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:700
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:395
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:454
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:689
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:289
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:6553
TAllRoutes::TLockedRouteClass::TruncateTrackVectorPosition
unsigned int TruncateTrackVectorPosition
the TrackVector position of the element selected for truncation
Definition: TrackUnit.h:1504
TOneRoute::GetRouteTruncateElement
void GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:15684
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:467
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:48
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:684
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1566
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:625
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5066
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:6465
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5093
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1389
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:505
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1527
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:64
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:826
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:847
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1645
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:741
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:9349
TTrack::TActiveLevelCrossing::ReducedTimePenalty
bool ReducedTimePenalty
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:532
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:15471
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:612
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:905
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:17891
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:351
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1557
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:523
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2436
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:484
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:470
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5222
TRailGraphics::LCBotHorMan
Graphics::TBitmap * LCBotHorMan
Definition: GraphicUnit.h:728
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:672
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:460
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:149
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:7343
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
limit to the number of elements searched in attempting to find a route
Definition: TrackUnit.h:1399
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:384
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:561
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:16598
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:763
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:497
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:666
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:11629
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:360
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:6846
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:483
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:401
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:8662
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:8534
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:12722
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:14040
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:566
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:16124
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:16959
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:857
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:855
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:494
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1508
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:873
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:548
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:11433
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:156
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:513
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:3992
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3251
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:673
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:831
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1411
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:459
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:582
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:760
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:466
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:796
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:7160
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:357
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:164
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:662
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:585
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:828
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4151
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1199
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:5752
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:9783
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:654
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:517
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:868
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3127
Unused
@ Unused
Definition: TrackUnit.h:63
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:587
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:617
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1198
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:490
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:705
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:17411
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2467
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:770
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:252
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:17602
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:493
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:8691
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1565
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1409
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1495
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:219
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:917
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:665
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:355
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:820
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:2855
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:14237
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:221
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:777
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:669
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:500
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Definition: TrackUnit.cpp:7604
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:11695
Simple
@ Simple
Definition: TrackUnit.h:63
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:693
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:444
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:40
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:478
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:794
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2483
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:627
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:1005
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:16710
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:775
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:819
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:425
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1231
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:706
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:11923
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1453
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:595
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5182
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:670
TTrain
Definition: TrainUnit.h:271
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:313
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:12589
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:504
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:96
TTrackElement::TrainIDOnBridgeTrackPos23
int TrainIDOnBridgeTrackPos23
Set to the TrainID value when a train is present on the element, bridges can have two trains present ...
Definition: TrackUnit.h:151
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:10391
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:493
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:561
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:489
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:842
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:542
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:6861
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:416
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:347
GapJump
@ GapJump
Definition: TrackUnit.h:63
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:443
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:790
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:17069
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:856
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:147
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:472
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:920
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:458
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:147
TTrack::Raising
@ Raising
Definition: TrackUnit.h:523
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:628
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:487
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:9418
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:557
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:78
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1413
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1377
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:698
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:366
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:638
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:499
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:695
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:386
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:761
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:453
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:715
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1275
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:5413
End
@ End
Definition: TrackUnit.h:73
TUserGraphicItem
Definition: DisplayUnit.h:31
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1415
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:668
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:843
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:534
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:7958
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:864
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:903
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:482
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackElement.at(At)
Definition: TrackUnit.cpp:9524
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1018
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:295
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:800
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:640
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:71
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:701
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:578
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:913
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:123
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:723
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:492
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:758
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3410
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:989
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:757
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:990
TPrefDirElement::PrefDirRoute
bool PrefDirRoute
marker within the route for preferred direction route element
Definition: TrackUnit.h:256
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:525
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:701
SignalPost
@ SignalPost
Definition: TrackUnit.h:63
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:8656
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:999
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:462
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:16112
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:421
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:778
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:863
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1531
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:792
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:827
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:6875
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:457
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
range for TInactiveTrack2MultiMap
Definition: TrackUnit.h:583
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:404
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:6157
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:254
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:491
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:685
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:36
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:7996
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:906
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:817
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:16097
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:756
Concourse
@ Concourse
Definition: TrackUnit.h:64
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:505
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:657
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:710
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:801
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:72
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:12379
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:12117
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:202
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:714
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:806
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:62
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:503
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4076
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1597
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:94
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:428
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:814
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:434
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:829
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:481
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:594
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:804
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:349
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:495
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:675
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:473
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:92
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:431
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:816
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:575
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:9968
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:16916
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4309
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:156
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1616
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:674
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:789
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:924
TTrack::SuppressRouteFailMessage
bool SuppressRouteFailMessage
true if a message has been given in the search routine, to avoid giving multiple times and to avoid o...
Definition: TrackUnit.h:654
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:477
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:90
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:586
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:720
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:835
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:382
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:10204
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:17508
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:505
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1016
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:611
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2451
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:710
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1421
TTrack::ResetAllTrainIDElements
void ResetAllTrainIDElements(int Caller)
Track elements have members that indicates whether and on what track a train is present (TrainIDOnEle...
Definition: TrackUnit.cpp:6832
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:13529
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:6581
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:7794
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:6660
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:667
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:721
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:605
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:660
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:284
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:596
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1201
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:757
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:803
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:510
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:802
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:470
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:12007
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:766
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:867
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:11182
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1532
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1584
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:904
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:588
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:11662
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:652
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:15888
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3228
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:141
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:12070
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:10251
TTrack::ThisNamedLocationLongEnoughForSplit
bool ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos, int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
See above under 'OneNamedLocationLongEnoughForSplit'.
Definition: TrackUnit.cpp:9656
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1499
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:764
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:818
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:496
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:496
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:5276
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:813
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:11482
Under
@ Under
Definition: TrackUnit.h:73
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:450
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller) const
Called by GetNextNonPreferredRouteElement and GetNextPreferredRouteElement to check whether or not an...
Definition: TrackUnit.cpp:15440
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:710
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:696
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:538
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:131
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2504
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:10403
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:10725
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:871
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:346
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:133
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:117
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:54
TTrack::OneNamedLocationLongEnoughForSplit
bool OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:9559
Lead
@ Lead
Definition: TrackUnit.h:73
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5141
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1533
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:12316
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:775
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:527
TTrack::WriteTrackToImage
void WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3436
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:217
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:4973
TTrack::IsBarrierDownVectorAtHVManual
bool IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
True if there is a vector entry at H & V that is set to manual (TypeOfRoute == 2) and returns the vec...
Definition: TrackUnit.cpp:5733
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:83
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1234
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:8468
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:468
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:469
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:579
TTrack::Up
@ Up
Definition: TrackUnit.h:523
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:863
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:712
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:500
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
Definition: TrackUnit.cpp:9538
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:923
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1371
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:339
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:7761
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1525
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:652
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:215
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:15955
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1515
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:363
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:781
Crossover
@ Crossover
Definition: TrackUnit.h:63
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:5620
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:475
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:446
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:714
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:623
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:7707
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:783
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:6609
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:9010
DefaultTrackLength
#define DefaultTrackLength
Definition: TrackUnit.h:37
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:452
Signal
@ Signal
Definition: TrackUnit.h:73
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:487
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:505
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:461
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:682
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:16400
TTrackElement::TrainIDOnBridgeTrackPos01
int TrainIDOnBridgeTrackPos01
Definition: TrackUnit.h:151
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1261
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:11532
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:506
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:10145
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4160
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:485
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackElement.at(At)
Definition: TrackUnit.cpp:9511
TGraphicElement::Width
int Width
Definition: TrackUnit.h:353
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:17295
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:520
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:17492
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:16225
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:687
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:488
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:731
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:570
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:532
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:447
TTrack::WriteOperatingTrackToImage
void WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track element graphics to the image file in...
Definition: TrackUnit.cpp:3720
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success and re...
Definition: Utilities.cpp:468
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:771
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:13129
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:570
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:3698
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2058
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:603
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:465
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:8592
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:11313
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:589
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:407
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:862
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:845
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5117
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:17575
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:568
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1413
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:910
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:769
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1402
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:828
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:6318
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:471
TTrack::LCFoundInRouteBuildingFlag
bool LCFoundInRouteBuildingFlag
true if a route set through an LC that is closed to trains (& therefore needs to be opened)
Definition: TrackUnit.h:656
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1029
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1031
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:514
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:7037
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:16045
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:571
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:422
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:6682
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:785
Erase
@ Erase
Definition: TrackUnit.h:64
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:832
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:398
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:480
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:4797
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:710
TAllRoutes::LockedRouteTruncateTrackVectorPosition
unsigned int LockedRouteTruncateTrackVectorPosition
Definition: TrackUnit.h:1564
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:123
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:812
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:859
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:576
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:12138
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:530
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:10058
Parapet
@ Parapet
Definition: TrackUnit.h:64
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:448
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:16070
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:65
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:786
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:993
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:277
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:8277
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:16020
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:378
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:852
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:710
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:16937
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:591
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:915
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
map of active track element names
Definition: TrackUnit.h:685
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:784
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:145
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:479
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:807
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:241
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:550
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1034
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:635
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:799
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:13655
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:824
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:135
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:217
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:10279
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:11240
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:505
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1179
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:497
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool PrefDirRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:15983
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:597
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:476
TRailGraphics::LCRHSVerMan
Graphics::TBitmap * LCRHSVerMan
Definition: GraphicUnit.h:732
TTrack
Definition: TrackUnit.h:463
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1242
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:757
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1249
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:17085
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1502
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:7312
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:621
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:503
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:841
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:651
TRailGraphics::LCBothHorMan
Graphics::TBitmap * LCBothHorMan
Definition: GraphicUnit.h:727
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:850
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:126
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:806
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:516
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:686
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:215
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:16576
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:223
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2583
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:451
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:7978
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:909
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:5514
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:1823
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:131
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:502
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:725
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:156
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:845
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:693
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2268
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:213
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1500
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:7009
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:482
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:11028
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:11785
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:501
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1377
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:9448
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:7670
IDInt
Definition: TrackUnit.h:412
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:2282
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:574
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:17543
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:598
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:779
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:3967
TDisplay
Definition: DisplayUnit.h:48
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:9258
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:4572
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:143
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:797
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:773
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:822
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:355
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:17640
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:894
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:8393
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:121
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:485
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:95
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:6958
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1180
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:221
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:151
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:886
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:671
TRailGraphics::LCPlainMan
Graphics::TBitmap * LCPlainMan
Definition: GraphicUnit.h:731
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:381
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:632
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:221
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:393
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:848
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:12921
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1569
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:154
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:128
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:768
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:6926
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:544
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:809
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:782
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:716
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:145
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:791
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:755
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1388
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:839
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1506
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:836
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1516
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:437
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4231
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:571
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Definition: TrackUnit.cpp:8216
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:644
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:14040
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1207
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:717
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:349
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:12244
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:813
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1186
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:149
Points
@ Points
Definition: TrackUnit.h:63
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:703
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:724
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:16650
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:854
TTrack::IsElementDefaultLength
bool IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
Definition: TrackUnit.cpp:8941
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:10128
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:410
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:583
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:821
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:499
Trail
@ Trail
Definition: TrackUnit.h:73
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:15932
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:8450
TOneRoute::SetRearwardsSignalsReturnFalseForTrain
bool SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:15552
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:762
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1569
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:498
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:40
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:805
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all points appropriately. Also called when a new train is added at...
Definition: TrackUnit.cpp:15377
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:818
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:648
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:419
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:726
Continuation
@ Continuation
Definition: TrackUnit.h:63
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1025
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:6805
GraphicUnit.h
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: InterfaceUnit.h:47
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3328
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:5353
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:86
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:505
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:356
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:8497
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:853
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:861
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:869
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:11071
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:491
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:823
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:753
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:858
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:349
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndSelectPosition, bool AutoSigsFlag)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:13565
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:505
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1014
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:2945
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:353
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:874
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1405
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:85
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:456
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:689
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:614
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:637
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1563
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:911
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:369
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:271
TRailGraphics::LCBothVerMan
Graphics::TBitmap * LCBothVerMan
Definition: GraphicUnit.h:729
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:294
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:837
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:17713
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:487
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:11971
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:1003
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:485
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:767
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1379
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:1007
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:84
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:350
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:449
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:677
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:616
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:785
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4216
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:872
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:16547
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1596
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:7808
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:699
TTrack::THVPairsLinkedMap
std::map< THVPair, bool > THVPairsLinkedMap
added at v2.6.1 for use in PopulateHVPairsLinkedMapAndNoDuplicates
Definition: TrackUnit.h:607
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:121
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:577
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:697
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:653
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:198
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
True if another train on NextEntryPos track of element at NextPos, whether bridge or not,...
Definition: TrackUnit.cpp:9922
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:811
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:618
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1244
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:17559
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:495
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1579
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4201
Connection
@ Connection
Definition: TrackUnit.h:73
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3305
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:359
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1571
TTrack::MarkOneLength
void MarkOneLength(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:8709
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:994
TRailGraphics::LCTopHorMan
Graphics::TBitmap * LCTopHorMan
Definition: GraphicUnit.h:733
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:501
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:15187
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:10902
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:707
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:810
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:7734
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:860
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1012
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:16861
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:16817
DefaultTrackSpeedLimit
#define DefaultTrackSpeedLimit
Definition: TrackUnit.h:38
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:6391
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:460
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:9809
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:692
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:851
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:631
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1232
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:883
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:486
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5161
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:844
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:708
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:445
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:254
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:349
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:664
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:9064
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:487
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:633
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:644
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:16084
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4341
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:788
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2371
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:675
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:6886
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:387
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:2711
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:375
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:840
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:130
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:865
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:372
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:15348
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:540
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:76
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:12496
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:265
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:349
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:662
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:590
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:604
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:614
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:394
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:489
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1180
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:565
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:463
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:575
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:899
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:625
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:10482
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:455
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:349
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:515
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:918
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:98
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1375
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:210
TTrack::PopulateHVPairsLinkedMapAndNoDuplicates
bool PopulateHVPairsLinkedMapAndNoDuplicates(int Caller, TLocationNameMultiMapRange LNMMRg)
Used in checking for duplicate location names after Bill78 (discord name) developed the ....
Definition: TrackUnit.cpp:7857
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:798
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1477
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:8036
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:626
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:572
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:622
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:12215
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:17527
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:139
TTrack::TBarrierState
TBarrierState
< state of barriers
Definition: TrackUnit.h:522
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1241
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4136
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:703
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4093
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1670
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:526
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1020
TTrack::SetBarriersDownLCToManual
void SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
Set TypeOfRoute value to 2 to indicate barriers manually closed.
Definition: TrackUnit.cpp:5660
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:991
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:695
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:63
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:825
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:627
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:6637
Platform
@ Platform
Definition: TrackUnit.h:63
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1249
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:223
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:577
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:870
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:668
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:640
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4118
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:679
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1510
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1027
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:765
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:921
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:7265
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:665
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1193
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:795
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:830
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:8630
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:1001
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:754
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:10023
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1484
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:815
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:55
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:624
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1377
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:348
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:14448
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:705
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:147
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:780
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:141
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:678
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1379
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:527
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:5676
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:709
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3205
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:757
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:643
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:98
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:111
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:498
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:787
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:650
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:9955
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:774
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:866
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:834
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:147
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:591
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:912
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:251
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:694
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:536
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:713
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:82
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:850
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:413
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:567
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:87
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:14805
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:598
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:708
RouteCall
@ RouteCall
Definition: TrackUnit.h:1186
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:388
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:10416
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:846
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:250
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:592
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:502
NotSet
@ NotSet
Definition: TrackUnit.h:73
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
iterator for TInactiveTrack2MultiMap
Definition: TrackUnit.h:581
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:17131
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:88
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:213
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:391
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:593
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:580
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:9984
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:9320
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:586
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:505
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:213
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:776
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:914
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:5578
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:156
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:64
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:922
TRailGraphics::smTransparent
Graphics::TBitmap * smTransparent
Definition: GraphicUnit.h:888
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:642
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:10428
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1246
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:392
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:141
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1243
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:838
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:722
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:808
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:693
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:487
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:615
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:9311
Bridge
@ Bridge
Definition: TrackUnit.h:63
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:849
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:440
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1180
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:797
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:524
Gap
@ Gap
Definition: TrackUnit.h:73
Buffers
@ Buffers
Definition: TrackUnit.h:63
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:15111
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:690
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:50
CrossConn
@ CrossConn
Definition: TrackUnit.h:73
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:10440
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:474
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4031
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:10363
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:833